From fe92ca33edee269283bbc04820443d338e4e41d7 Mon Sep 17 00:00:00 2001 From: Vasudev Kamath Date: Thu, 25 Jan 2018 14:57:43 +0530 Subject: [PATCH 1/1] Import cargo_0.24.0.orig-vendor.tar.gz [dgit import orig cargo_0.24.0.orig-vendor.tar.gz] --- advapi32-sys-0.2.0/.cargo-checksum.json | 1 + advapi32-sys-0.2.0/Cargo.toml | 17 + advapi32-sys-0.2.0/README.md | 13 + advapi32-sys-0.2.0/build.rs | 6 + advapi32-sys-0.2.0/src/lib.rs | 1005 + aho-corasick-0.5.3/.cargo-checksum.json | 1 + aho-corasick-0.5.3/.travis.yml | 12 + aho-corasick-0.5.3/COPYING | 3 + aho-corasick-0.5.3/Cargo.toml | 46 + aho-corasick-0.5.3/LICENSE-MIT | 21 + aho-corasick-0.5.3/Makefile | 14 + aho-corasick-0.5.3/README.md | 55 + aho-corasick-0.5.3/UNLICENSE | 24 + aho-corasick-0.5.3/benches/bench.rs | 339 + aho-corasick-0.5.3/benches/random.txt | 513 + aho-corasick-0.5.3/benches/sherlock.txt | 13052 +++++++++ aho-corasick-0.5.3/ctags.rust | 11 + aho-corasick-0.5.3/examples/dict-search.rs | 151 + aho-corasick-0.5.3/session.vim | 1 + aho-corasick-0.5.3/src/autiter.rs | 503 + aho-corasick-0.5.3/src/full.rs | 136 + aho-corasick-0.5.3/src/lib.rs | 925 + aho-corasick-0.5.3/src/main.rs | 13 + aho-corasick-0.6.4/.cargo-checksum.json | 1 + aho-corasick-0.6.4/.travis.yml | 13 + aho-corasick-0.6.4/COPYING | 3 + aho-corasick-0.6.4/Cargo.toml | 68 + aho-corasick-0.6.4/LICENSE-MIT | 21 + aho-corasick-0.6.4/Makefile | 14 + aho-corasick-0.6.4/README.md | 55 + aho-corasick-0.6.4/UNLICENSE | 24 + aho-corasick-0.6.4/benches/bench.rs | 339 + aho-corasick-0.6.4/benches/random.txt | 513 + aho-corasick-0.6.4/ctags.rust | 11 + aho-corasick-0.6.4/examples/dict-search.rs | 151 + aho-corasick-0.6.4/session.vim | 1 + aho-corasick-0.6.4/src/autiter.rs | 530 + aho-corasick-0.6.4/src/full.rs | 136 + aho-corasick-0.6.4/src/lib.rs | 925 + aho-corasick-0.6.4/src/main.rs | 13 + atty-0.2.6/.cargo-checksum.json | 1 + atty-0.2.6/.travis.yml | 73 + atty-0.2.6/CHANGELOG.md | 41 + atty-0.2.6/Cargo.toml | 33 + atty-0.2.6/LICENSE | 20 + atty-0.2.6/README.md | 78 + atty-0.2.6/appveyor.yml | 16 + atty-0.2.6/examples/atty.rs | 9 + atty-0.2.6/rustfmt.toml | 10 + atty-0.2.6/src/lib.rs | 210 + backtrace-0.3.5/.cargo-checksum.json | 1 + backtrace-0.3.5/.travis.yml | 60 + backtrace-0.3.5/Cargo.toml | 74 + backtrace-0.3.5/LICENSE-APACHE | 201 + backtrace-0.3.5/LICENSE-MIT | 25 + backtrace-0.3.5/README.md | 91 + backtrace-0.3.5/appveyor.yml | 20 + backtrace-0.3.5/examples/backtrace.rs | 7 + backtrace-0.3.5/examples/raw.rs | 48 + backtrace-0.3.5/src/backtrace/dbghelp.rs | 103 + backtrace-0.3.5/src/backtrace/libunwind.rs | 200 + backtrace-0.3.5/src/backtrace/mod.rs | 113 + backtrace-0.3.5/src/backtrace/noop.rs | 16 + .../src/backtrace/unix_backtrace.rs | 46 + backtrace-0.3.5/src/capture.rs | 237 + backtrace-0.3.5/src/dylib.rs | 70 + backtrace-0.3.5/src/lib.rs | 177 + .../src/symbolize/coresymbolication.rs | 192 + backtrace-0.3.5/src/symbolize/dbghelp.rs | 118 + backtrace-0.3.5/src/symbolize/dladdr.rs | 59 + backtrace-0.3.5/src/symbolize/gimli.rs | 170 + backtrace-0.3.5/src/symbolize/libbacktrace.rs | 180 + backtrace-0.3.5/src/symbolize/mod.rs | 290 + backtrace-0.3.5/src/symbolize/noop.rs | 27 + backtrace-0.3.5/tests/long_fn_name.rs | 57 + backtrace-0.3.5/tests/smoke.rs | 171 + backtrace-sys-0.1.16/.cargo-checksum.json | 1 + backtrace-sys-0.1.16/Cargo.toml | 26 + backtrace-sys-0.1.16/build.rs | 178 + backtrace-sys-0.1.16/src/lib.rs | 44 + .../src/libbacktrace/ChangeLog | 598 + .../src/libbacktrace/ChangeLog.jit | 14 + .../src/libbacktrace/Makefile.am | 136 + .../src/libbacktrace/Makefile.in | 770 + backtrace-sys-0.1.16/src/libbacktrace/README | 23 + .../src/libbacktrace/aclocal.m4 | 683 + backtrace-sys-0.1.16/src/libbacktrace/alloc.c | 156 + .../src/libbacktrace/ansidecl.h | 355 + .../src/libbacktrace/atomic.c | 113 + .../src/libbacktrace/backtrace-supported.h.in | 66 + .../src/libbacktrace/backtrace.c | 129 + .../src/libbacktrace/backtrace.h | 199 + backtrace-sys-0.1.16/src/libbacktrace/btest.c | 721 + .../src/libbacktrace/config.guess | 1462 + .../src/libbacktrace/config.h.in | 134 + .../src/libbacktrace/config.sub | 1825 ++ .../src/libbacktrace/configure | 15189 ++++++++++ .../src/libbacktrace/configure.ac | 409 + backtrace-sys-0.1.16/src/libbacktrace/dwarf.c | 3038 ++ .../src/libbacktrace/dwarf2.def | 773 + .../src/libbacktrace/dwarf2.h | 531 + backtrace-sys-0.1.16/src/libbacktrace/elf.c | 979 + .../src/libbacktrace/fileline.c | 194 + .../src/libbacktrace/filenames.h | 99 + .../src/libbacktrace/filetype.awk | 5 + .../src/libbacktrace/hashtab.h | 204 + .../src/libbacktrace/install-sh | 501 + .../src/libbacktrace/internal.h | 294 + .../src/libbacktrace/ltmain.sh | 8636 ++++++ backtrace-sys-0.1.16/src/libbacktrace/missing | 215 + backtrace-sys-0.1.16/src/libbacktrace/mmap.c | 303 + .../src/libbacktrace/mmapio.c | 100 + .../src/libbacktrace/nounwind.c | 66 + .../src/libbacktrace/pecoff.c | 937 + backtrace-sys-0.1.16/src/libbacktrace/posix.c | 100 + backtrace-sys-0.1.16/src/libbacktrace/print.c | 92 + backtrace-sys-0.1.16/src/libbacktrace/read.c | 96 + .../src/libbacktrace/simple.c | 108 + backtrace-sys-0.1.16/src/libbacktrace/sort.c | 108 + backtrace-sys-0.1.16/src/libbacktrace/state.c | 72 + backtrace-sys-0.1.16/src/libbacktrace/stest.c | 137 + .../src/libbacktrace/unknown.c | 64 + backtrace-sys-0.1.16/symbol-map | 18 + bitflags-0.9.1/.cargo-checksum.json | 1 + bitflags-0.9.1/.travis.yml | 29 + bitflags-0.9.1/Cargo.toml | 31 + bitflags-0.9.1/LICENSE-APACHE | 201 + bitflags-0.9.1/LICENSE-MIT | 25 + bitflags-0.9.1/README.md | 24 + bitflags-0.9.1/src/example_generated.rs | 16 + bitflags-0.9.1/src/lib.rs | 990 + .../tests/conflicting_trait_impls.rs | 20 + bitflags-0.9.1/tests/external.rs | 21 + bitflags-0.9.1/tests/external_no_std.rs | 22 + bitflags-0.9.1/tests/i128_bitflags.rs | 30 + bitflags-1.0.1/.cargo-checksum.json | 1 + bitflags-1.0.1/.travis.yml | 23 + bitflags-1.0.1/CHANGELOG.md | 64 + bitflags-1.0.1/Cargo.toml | 30 + bitflags-1.0.1/LICENSE-APACHE | 201 + bitflags-1.0.1/LICENSE-MIT | 25 + bitflags-1.0.1/README.md | 29 + bitflags-1.0.1/src/example_generated.rs | 14 + bitflags-1.0.1/src/lib.rs | 1160 + bufstream-0.1.3/.cargo-checksum.json | 1 + bufstream-0.1.3/.travis.yml | 24 + bufstream-0.1.3/Cargo.toml | 23 + bufstream-0.1.3/LICENSE-APACHE | 201 + bufstream-0.1.3/LICENSE-MIT | 25 + bufstream-0.1.3/README.md | 22 + bufstream-0.1.3/src/lib.rs | 262 + cc-1.0.4/.cargo-checksum.json | 1 + cc-1.0.4/.travis.yml | 53 + cc-1.0.4/Cargo.toml | 37 + cc-1.0.4/LICENSE-APACHE | 201 + cc-1.0.4/LICENSE-MIT | 25 + cc-1.0.4/README.md | 202 + cc-1.0.4/appveyor.yml | 55 + cc-1.0.4/src/bin/gcc-shim.rs | 23 + cc-1.0.4/src/com.rs | 125 + cc-1.0.4/src/lib.rs | 1998 ++ cc-1.0.4/src/registry.rs | 190 + cc-1.0.4/src/setup_config.rs | 257 + cc-1.0.4/src/winapi.rs | 214 + cc-1.0.4/src/windows_registry.rs | 634 + cc-1.0.4/tests/cc_env.rs | 73 + cc-1.0.4/tests/support/mod.rs | 122 + cc-1.0.4/tests/test.rs | 351 + cfg-if-0.1.2/.cargo-checksum.json | 1 + cfg-if-0.1.2/.travis.yml | 23 + cfg-if-0.1.2/Cargo.toml | 14 + cfg-if-0.1.2/LICENSE-APACHE | 201 + cfg-if-0.1.2/LICENSE-MIT | 25 + cfg-if-0.1.2/README.md | 44 + cfg-if-0.1.2/src/lib.rs | 133 + cfg-if-0.1.2/tests/xcrate.rs | 17 + cmake-0.1.29/.cargo-checksum.json | 1 + cmake-0.1.29/.travis.yml | 20 + cmake-0.1.29/Cargo.toml | 25 + cmake-0.1.29/LICENSE-APACHE | 201 + cmake-0.1.29/LICENSE-MIT | 25 + cmake-0.1.29/README.md | 34 + cmake-0.1.29/src/lib.rs | 633 + commoncrypto-0.2.0/.cargo-checksum.json | 1 + commoncrypto-0.2.0/Cargo.toml | 20 + commoncrypto-0.2.0/src/hash.rs | 127 + commoncrypto-0.2.0/src/lib.rs | 30 + commoncrypto-0.2.0/src/pbkdf2.rs | 66 + commoncrypto-0.2.0/tests/hash.rs | 18 + commoncrypto-0.2.0/tests/pbkdf2.rs | 16 + commoncrypto-sys-0.2.0/.cargo-checksum.json | 1 + commoncrypto-sys-0.2.0/Cargo.toml | 20 + commoncrypto-sys-0.2.0/src/lib.rs | 237 + commoncrypto-sys-0.2.0/tests/hash.rs | 138 + commoncrypto-sys-0.2.0/tests/pbkdf2.rs | 48 + core-foundation-0.4.6/.cargo-checksum.json | 1 + core-foundation-0.4.6/Cargo.toml | 39 + core-foundation-0.4.6/src/array.rs | 235 + core-foundation-0.4.6/src/base.rs | 197 + core-foundation-0.4.6/src/boolean.rs | 77 + core-foundation-0.4.6/src/bundle.rs | 127 + core-foundation-0.4.6/src/data.rs | 69 + core-foundation-0.4.6/src/date.rs | 136 + core-foundation-0.4.6/src/dictionary.rs | 133 + core-foundation-0.4.6/src/error.rs | 77 + core-foundation-0.4.6/src/lib.rs | 222 + core-foundation-0.4.6/src/number.rs | 146 + core-foundation-0.4.6/src/propertylist.rs | 255 + core-foundation-0.4.6/src/runloop.rs | 212 + core-foundation-0.4.6/src/set.rs | 46 + core-foundation-0.4.6/src/string.rs | 149 + core-foundation-0.4.6/src/timezone.rs | 101 + core-foundation-0.4.6/src/url.rs | 164 + core-foundation-0.4.6/src/uuid.rs | 118 + .../.cargo-checksum.json | 1 + core-foundation-sys-0.4.6/Cargo.toml | 27 + core-foundation-sys-0.4.6/build.rs | 14 + core-foundation-sys-0.4.6/src/array.rs | 55 + core-foundation-sys-0.4.6/src/base.rs | 127 + core-foundation-sys-0.4.6/src/bundle.rs | 36 + core-foundation-sys-0.4.6/src/data.rs | 22 + core-foundation-sys-0.4.6/src/date.rs | 34 + core-foundation-sys-0.4.6/src/dictionary.rs | 77 + core-foundation-sys-0.4.6/src/error.rs | 32 + core-foundation-sys-0.4.6/src/lib.rs | 30 + core-foundation-sys-0.4.6/src/messageport.rs | 79 + core-foundation-sys-0.4.6/src/number.rs | 60 + core-foundation-sys-0.4.6/src/propertylist.rs | 37 + core-foundation-sys-0.4.6/src/runloop.rs | 164 + core-foundation-sys-0.4.6/src/set.rs | 58 + core-foundation-sys-0.4.6/src/string.rs | 319 + core-foundation-sys-0.4.6/src/timezone.rs | 27 + core-foundation-sys-0.4.6/src/url.rs | 163 + core-foundation-sys-0.4.6/src/uuid.rs | 48 + crossbeam-0.2.12/.cargo-checksum.json | 1 + crossbeam-0.2.12/.travis.yml | 36 + crossbeam-0.2.12/CHANGELOG.md | 11 + crossbeam-0.2.12/Cargo.toml | 26 + crossbeam-0.2.12/LICENSE-APACHE | 201 + crossbeam-0.2.12/LICENSE-MIT | 25 + crossbeam-0.2.12/README.md | 38 + crossbeam-0.2.12/scala-bench/bench.scala | 195 + crossbeam-0.2.12/src/bin/bench.rs | 165 + crossbeam-0.2.12/src/bin/extra_impls/mod.rs | 1 + .../src/bin/extra_impls/mpsc_queue.rs | 155 + crossbeam-0.2.12/src/bin/stress-msq.rs | 36 + crossbeam-0.2.12/src/lib.rs | 54 + crossbeam-0.2.12/src/mem/cache_padded.rs | 164 + crossbeam-0.2.12/src/mem/epoch/atomic.rs | 181 + crossbeam-0.2.12/src/mem/epoch/garbage.rs | 144 + crossbeam-0.2.12/src/mem/epoch/global.rs | 95 + crossbeam-0.2.12/src/mem/epoch/guard.rs | 56 + crossbeam-0.2.12/src/mem/epoch/local.rs | 38 + crossbeam-0.2.12/src/mem/epoch/mod.rs | 265 + crossbeam-0.2.12/src/mem/epoch/participant.rs | 133 + .../src/mem/epoch/participants.rs | 120 + crossbeam-0.2.12/src/mem/mod.rs | 9 + crossbeam-0.2.12/src/scoped.rs | 275 + crossbeam-0.2.12/src/sync/arc_cell.rs | 90 + crossbeam-0.2.12/src/sync/atomic_option.rs | 38 + crossbeam-0.2.12/src/sync/chase_lev.rs | 602 + crossbeam-0.2.12/src/sync/mod.rs | 14 + crossbeam-0.2.12/src/sync/ms_queue.rs | 511 + crossbeam-0.2.12/src/sync/seg_queue.rs | 251 + crossbeam-0.2.12/src/sync/treiber_stack.rs | 98 + crossbeam-0.3.2/.cargo-checksum.json | 1 + crossbeam-0.3.2/.travis.yml | 36 + crossbeam-0.3.2/CHANGELOG.md | 22 + crossbeam-0.3.2/Cargo.toml | 27 + crossbeam-0.3.2/LICENSE-APACHE | 201 + crossbeam-0.3.2/LICENSE-MIT | 25 + crossbeam-0.3.2/README.md | 46 + crossbeam-0.3.2/src/bin/bench.rs | 159 + crossbeam-0.3.2/src/bin/extra_impls/mod.rs | 1 + .../src/bin/extra_impls/mpsc_queue.rs | 155 + crossbeam-0.3.2/src/bin/stress-msq.rs | 36 + crossbeam-0.3.2/src/cache_padded.rs | 164 + crossbeam-0.3.2/src/epoch/atomic.rs | 181 + crossbeam-0.3.2/src/epoch/garbage.rs | 144 + crossbeam-0.3.2/src/epoch/global.rs | 95 + crossbeam-0.3.2/src/epoch/guard.rs | 56 + crossbeam-0.3.2/src/epoch/local.rs | 38 + crossbeam-0.3.2/src/epoch/mod.rs | 265 + crossbeam-0.3.2/src/epoch/participant.rs | 133 + crossbeam-0.3.2/src/epoch/participants.rs | 120 + crossbeam-0.3.2/src/lib.rs | 68 + crossbeam-0.3.2/src/scoped.rs | 314 + crossbeam-0.3.2/src/sync/arc_cell.rs | 90 + crossbeam-0.3.2/src/sync/atomic_option.rs | 49 + crossbeam-0.3.2/src/sync/chase_lev.rs | 605 + crossbeam-0.3.2/src/sync/mod.rs | 14 + crossbeam-0.3.2/src/sync/ms_queue.rs | 526 + crossbeam-0.3.2/src/sync/seg_queue.rs | 289 + crossbeam-0.3.2/src/sync/treiber_stack.rs | 110 + crypt32-sys-0.2.0/.cargo-checksum.json | 1 + crypt32-sys-0.2.0/Cargo.toml | 18 + crypt32-sys-0.2.0/README.md | 13 + crypt32-sys-0.2.0/build.rs | 6 + crypt32-sys-0.2.0/src/lib.rs | 796 + crypto-hash-0.3.0/.cargo-checksum.json | 1 + crypto-hash-0.3.0/CONTRIBUTING.md | 77 + crypto-hash-0.3.0/Cargo.toml | 31 + crypto-hash-0.3.0/LICENSE | 19 + crypto-hash-0.3.0/Makefile | 29 + crypto-hash-0.3.0/NEWS.md | 49 + crypto-hash-0.3.0/README.md | 54 + crypto-hash-0.3.0/src/imp/commoncrypto.rs | 81 + crypto-hash-0.3.0/src/imp/cryptoapi.rs | 154 + crypto-hash-0.3.0/src/imp/openssl.rs | 85 + crypto-hash-0.3.0/src/lib.rs | 122 + crypto-hash-0.3.0/src/test.rs | 79 + curl-0.4.11/.cargo-checksum.json | 1 + curl-0.4.11/.gitmodules | 3 + curl-0.4.11/.travis.yml | 69 + curl-0.4.11/Cargo.toml | 49 + curl-0.4.11/LICENSE | 19 + curl-0.4.11/README.md | 137 + curl-0.4.11/appveyor.yml | 69 + curl-0.4.11/ci/.cargo/config | 2 + curl-0.4.11/ci/Dockerfile-linux32 | 14 + curl-0.4.11/ci/Dockerfile-linux64 | 9 + curl-0.4.11/ci/Dockerfile-linux64-curl | 6 + curl-0.4.11/ci/Dockerfile-mingw | 6 + curl-0.4.11/ci/Dockerfile-musl | 18 + curl-0.4.11/ci/run.sh | 16 + curl-0.4.11/src/easy/form.rs | 333 + curl-0.4.11/src/easy/handle.rs | 1446 + curl-0.4.11/src/easy/handler.rs | 3142 +++ curl-0.4.11/src/easy/list.rs | 99 + curl-0.4.11/src/easy/mod.rs | 22 + curl-0.4.11/src/easy/windows.rs | 136 + curl-0.4.11/src/error.rs | 598 + curl-0.4.11/src/lib.rs | 128 + curl-0.4.11/src/multi.rs | 928 + curl-0.4.11/src/panic.rs | 30 + curl-0.4.11/src/version.rs | 303 + curl-0.4.11/tests/easy.rs | 693 + curl-0.4.11/tests/formdata | 1 + curl-0.4.11/tests/multi.rs | 252 + curl-0.4.11/tests/post.rs | 109 + curl-0.4.11/tests/server/mod.rs | 175 + curl-sys-0.4.1/.cargo-checksum.json | 1 + curl-sys-0.4.1/Cargo.toml | 49 + curl-sys-0.4.1/LICENSE | 19 + curl-sys-0.4.1/build.rs | 420 + curl-sys-0.4.1/lib.rs | 1052 + docopt-0.8.3/.cargo-checksum.json | 1 + docopt-0.8.3/.travis.yml | 15 + docopt-0.8.3/COPYING | 3 + docopt-0.8.3/Cargo.toml | 47 + docopt-0.8.3/LICENSE-MIT | 21 + docopt-0.8.3/Makefile | 18 + docopt-0.8.3/README.md | 357 + docopt-0.8.3/UNLICENSE | 24 + docopt-0.8.3/completions/docopt-wordlist.bash | 79 + docopt-0.8.3/ctags.rust | 11 + docopt-0.8.3/examples/cargo.rs | 59 + docopt-0.8.3/examples/cp.rs | 29 + docopt-0.8.3/examples/decode.rs | 48 + docopt-0.8.3/examples/hashmap.rs | 39 + docopt-0.8.3/examples/optional_command.rs | 76 + docopt-0.8.3/examples/verbose_multiple.rs | 37 + docopt-0.8.3/scripts/mk-testcases | 80 + docopt-0.8.3/session.vim | 3 + docopt-0.8.3/src/dopt.rs | 1006 + docopt-0.8.3/src/lib.rs | 269 + docopt-0.8.3/src/parse.rs | 1488 + docopt-0.8.3/src/synonym.rs | 107 + docopt-0.8.3/src/test/mod.rs | 152 + docopt-0.8.3/src/test/suggestions.rs | 72 + docopt-0.8.3/src/test/testcases.docopt | 1122 + docopt-0.8.3/src/test/testcases.rs | 801 + docopt-0.8.3/src/wordlist.rs | 114 + dtoa-0.4.2/.cargo-checksum.json | 1 + dtoa-0.4.2/.travis.yml | 6 + dtoa-0.4.2/Cargo.toml | 23 + dtoa-0.4.2/LICENSE-APACHE | 201 + dtoa-0.4.2/LICENSE-MIT | 25 + dtoa-0.4.2/README.md | 69 + dtoa-0.4.2/benches/bench.rs | 54 + dtoa-0.4.2/src/diyfp.rs | 232 + dtoa-0.4.2/src/dtoa.rs | 479 + dtoa-0.4.2/src/lib.rs | 148 + dtoa-0.4.2/tests/test.rs | 38 + env_logger-0.4.3/.cargo-checksum.json | 1 + env_logger-0.4.3/Cargo.toml | 35 + env_logger-0.4.3/LICENSE-APACHE | 201 + env_logger-0.4.3/LICENSE-MIT | 25 + env_logger-0.4.3/src/lib.rs | 652 + env_logger-0.4.3/src/regex.rs | 28 + env_logger-0.4.3/src/string.rs | 21 + env_logger-0.4.3/tests/regexp_filter.rs | 51 + error-chain-0.11.0/.cargo-checksum.json | 1 + error-chain-0.11.0/.travis.yml | 46 + error-chain-0.11.0/CHANGELOG.md | 120 + error-chain-0.11.0/Cargo.toml | 32 + error-chain-0.11.0/LICENSE-APACHE | 201 + error-chain-0.11.0/LICENSE-MIT | 26 + error-chain-0.11.0/README.md | 36 + error-chain-0.11.0/examples/all.rs | 36 + error-chain-0.11.0/examples/chain_err.rs | 69 + error-chain-0.11.0/examples/doc.rs | 28 + error-chain-0.11.0/examples/quickstart.rs | 80 + error-chain-0.11.0/examples/size.rs | 38 + error-chain-0.11.0/src/bin/has_backtrace.rs | 18 + error-chain-0.11.0/src/error_chain.rs | 458 + error-chain-0.11.0/src/example_generated.rs | 38 + .../src/impl_error_chain_kind.rs | 541 + error-chain-0.11.0/src/lib.rs | 865 + error-chain-0.11.0/src/quick_main.rs | 77 + error-chain-0.11.0/tests/quick_main.rs | 28 + error-chain-0.11.0/tests/tests.rs | 628 + filetime-0.1.14/.cargo-checksum.json | 1 + filetime-0.1.14/.travis.yml | 26 + filetime-0.1.14/Cargo.toml | 31 + filetime-0.1.14/LICENSE-APACHE | 201 + filetime-0.1.14/LICENSE-MIT | 25 + filetime-0.1.14/README.md | 25 + filetime-0.1.14/appveyor.yml | 17 + filetime-0.1.14/src/lib.rs | 286 + filetime-0.1.14/src/redox.rs | 57 + filetime-0.1.14/src/unix/linux.rs | 45 + filetime-0.1.14/src/unix/mod.rs | 125 + filetime-0.1.14/src/unix/utimensat.rs | 13 + filetime-0.1.14/src/unix/utimes.rs | 13 + filetime-0.1.14/src/windows.rs | 87 + flate2-0.2.20/.cargo-checksum.json | 1 + flate2-0.2.20/.travis.yml | 32 + flate2-0.2.20/Cargo.toml | 61 + flate2-0.2.20/LICENSE-APACHE | 201 + flate2-0.2.20/LICENSE-MIT | 25 + flate2-0.2.20/README.md | 70 + flate2-0.2.20/appveyor.yml | 24 + .../examples/deflatedecoder-bufread.rs | 24 + flate2-0.2.20/examples/deflatedecoder-read.rs | 24 + .../examples/deflatedecoder-write.rs | 26 + .../examples/deflateencoder-bufread.rs | 24 + flate2-0.2.20/examples/deflateencoder-read.rs | 20 + .../examples/deflateencoder-write.rs | 12 + flate2-0.2.20/examples/flatereadext.rs | 22 + flate2-0.2.20/examples/gzbuilder.rs | 24 + flate2-0.2.20/examples/gzdecoder-bufread.rs | 24 + flate2-0.2.20/examples/gzdecoder-read.rs | 24 + flate2-0.2.20/examples/gzencoder-bufread.rs | 24 + flate2-0.2.20/examples/gzencoder-read.rs | 20 + flate2-0.2.20/examples/gzencoder-write.rs | 12 + .../examples/gzmultidecoder-bufread.rs | 24 + flate2-0.2.20/examples/gzmultidecoder-read.rs | 24 + flate2-0.2.20/examples/hello_world.txt | 1 + flate2-0.2.20/examples/zlibdecoder-bufread.rs | 24 + flate2-0.2.20/examples/zlibdecoder-read.rs | 24 + flate2-0.2.20/examples/zlibdecoder-write.rs | 26 + flate2-0.2.20/examples/zlibencoder-bufread.rs | 24 + flate2-0.2.20/examples/zlibencoder-read.rs | 21 + flate2-0.2.20/examples/zlibencoder-write.rs | 12 + flate2-0.2.20/src/bufreader.rs | 98 + flate2-0.2.20/src/crc.rs | 124 + flate2-0.2.20/src/deflate/bufread.rs | 269 + flate2-0.2.20/src/deflate/mod.rs | 198 + flate2-0.2.20/src/deflate/read.rs | 268 + flate2-0.2.20/src/deflate/write.rs | 350 + flate2-0.2.20/src/ffi.rs | 235 + flate2-0.2.20/src/gz/bufread.rs | 547 + flate2-0.2.20/src/gz/mod.rs | 344 + flate2-0.2.20/src/gz/read.rs | 286 + flate2-0.2.20/src/gz/write.rs | 182 + flate2-0.2.20/src/lib.rs | 308 + flate2-0.2.20/src/mem.rs | 516 + flate2-0.2.20/src/zio.rs | 201 + flate2-0.2.20/src/zlib/bufread.rs | 259 + flate2-0.2.20/src/zlib/mod.rs | 164 + flate2-0.2.20/src/zlib/read.rs | 266 + flate2-0.2.20/src/zlib/write.rs | 351 + flate2-0.2.20/tests/corrupt-file.gz | Bin 0 -> 7128 bytes flate2-0.2.20/tests/early-flush.rs | 20 + flate2-0.2.20/tests/good-file.gz | Bin 0 -> 6766 bytes flate2-0.2.20/tests/good-file.txt | 733 + flate2-0.2.20/tests/gunzip.rs | 59 + flate2-0.2.20/tests/multi.gz | Bin 0 -> 53 bytes flate2-0.2.20/tests/multi.txt | 2 + flate2-0.2.20/tests/tokio.rs | 125 + flate2-0.2.20/tests/zero-write.rs | 8 + fnv-1.0.6/.cargo-checksum.json | 1 + fnv-1.0.6/.travis.yml | 8 + fnv-1.0.6/Cargo.toml | 25 + fnv-1.0.6/LICENSE-APACHE | 201 + fnv-1.0.6/LICENSE-MIT | 25 + fnv-1.0.6/README.md | 81 + fnv-1.0.6/lib.rs | 349 + foreign-types-0.3.2/.cargo-checksum.json | 1 + foreign-types-0.3.2/Cargo.toml | 22 + foreign-types-0.3.2/LICENSE-APACHE | 202 + foreign-types-0.3.2/LICENSE-MIT | 19 + foreign-types-0.3.2/README.md | 23 + foreign-types-0.3.2/src/lib.rs | 306 + .../.cargo-checksum.json | 1 + foreign-types-shared-0.1.1/Cargo.toml | 21 + foreign-types-shared-0.1.1/LICENSE-APACHE | 202 + foreign-types-shared-0.1.1/LICENSE-MIT | 19 + foreign-types-shared-0.1.1/src/lib.rs | 51 + fs2-0.4.3/.appveyor.yml | 18 + fs2-0.4.3/.cargo-checksum.json | 1 + fs2-0.4.3/.travis.yml | 21 + fs2-0.4.3/Cargo.toml | 33 + fs2-0.4.3/LICENSE-APACHE | 201 + fs2-0.4.3/LICENSE-MIT | 25 + fs2-0.4.3/README.md | 50 + fs2-0.4.3/src/lib.rs | 458 + fs2-0.4.3/src/unix.rs | 250 + fs2-0.4.3/src/windows.rs | 279 + fuchsia-zircon-0.3.3/.cargo-checksum.json | 1 + fuchsia-zircon-0.3.3/BUILD.gn | 14 + fuchsia-zircon-0.3.3/Cargo.toml | 24 + fuchsia-zircon-0.3.3/LICENSE | 27 + fuchsia-zircon-0.3.3/README.md | 12 + fuchsia-zircon-0.3.3/examples/BUILD.gn | 17 + fuchsia-zircon-0.3.3/src/channel.rs | 418 + fuchsia-zircon-0.3.3/src/cprng.rs | 68 + fuchsia-zircon-0.3.3/src/event.rs | 32 + fuchsia-zircon-0.3.3/src/eventpair.rs | 65 + fuchsia-zircon-0.3.3/src/fifo.rs | 98 + fuchsia-zircon-0.3.3/src/handle.rs | 243 + fuchsia-zircon-0.3.3/src/job.rs | 14 + fuchsia-zircon-0.3.3/src/lib.rs | 365 + fuchsia-zircon-0.3.3/src/port.rs | 344 + fuchsia-zircon-0.3.3/src/process.rs | 14 + fuchsia-zircon-0.3.3/src/rights.rs | 28 + fuchsia-zircon-0.3.3/src/signals.rs | 105 + fuchsia-zircon-0.3.3/src/socket.rs | 126 + fuchsia-zircon-0.3.3/src/status.rs | 162 + fuchsia-zircon-0.3.3/src/thread.rs | 14 + fuchsia-zircon-0.3.3/src/time.rs | 346 + fuchsia-zircon-0.3.3/src/vmar.rs | 18 + fuchsia-zircon-0.3.3/src/vmo.rs | 256 + fuchsia-zircon-0.3.3/tools/gen_status.py | 49 + fuchsia-zircon-sys-0.3.3/.cargo-checksum.json | 1 + fuchsia-zircon-sys-0.3.3/BUILD.gn | 9 + fuchsia-zircon-sys-0.3.3/Cargo.toml | 19 + fuchsia-zircon-sys-0.3.3/examples/hello.rs | 14 + fuchsia-zircon-sys-0.3.3/src/definitions.rs | 903 + fuchsia-zircon-sys-0.3.3/src/lib.rs | 474 + git2-0.6.11/.cargo-checksum.json | 1 + git2-0.6.11/.gitmodules | 3 + git2-0.6.11/.travis.yml | 54 + git2-0.6.11/Cargo.toml | 68 + git2-0.6.11/LICENSE-APACHE | 201 + git2-0.6.11/LICENSE-MIT | 25 + git2-0.6.11/README.md | 57 + git2-0.6.11/appveyor.yml | 23 + git2-0.6.11/examples/add.rs | 85 + git2-0.6.11/examples/blame.rs | 106 + git2-0.6.11/examples/cat-file.rs | 142 + git2-0.6.11/examples/clone.rs | 124 + git2-0.6.11/examples/diff.rs | 284 + git2-0.6.11/examples/fetch.rs | 128 + git2-0.6.11/examples/init.rs | 152 + git2-0.6.11/examples/log.rs | 263 + git2-0.6.11/examples/ls-remote.rs | 63 + git2-0.6.11/examples/rev-list.rs | 97 + git2-0.6.11/examples/rev-parse.rs | 70 + git2-0.6.11/examples/status.rs | 369 + git2-0.6.11/examples/tag.rs | 134 + git2-0.6.11/src/blame.rs | 315 + git2-0.6.11/src/blob.rs | 186 + git2-0.6.11/src/branch.rs | 162 + git2-0.6.11/src/buf.rs | 73 + git2-0.6.11/src/build.rs | 638 + git2-0.6.11/src/call.rs | 217 + git2-0.6.11/src/cert.rs | 97 + git2-0.6.11/src/commit.rs | 359 + git2-0.6.11/src/config.rs | 608 + git2-0.6.11/src/cred.rs | 465 + git2-0.6.11/src/describe.rs | 199 + git2-0.6.11/src/diff.rs | 1250 + git2-0.6.11/src/error.rs | 284 + git2-0.6.11/src/index.rs | 634 + git2-0.6.11/src/lib.rs | 1165 + git2-0.6.11/src/merge.rs | 160 + git2-0.6.11/src/message.rs | 52 + git2-0.6.11/src/note.rs | 130 + git2-0.6.11/src/object.rs | 234 + git2-0.6.11/src/odb.rs | 285 + git2-0.6.11/src/oid.rs | 140 + git2-0.6.11/src/oid_array.rs | 50 + git2-0.6.11/src/packbuilder.rs | 386 + git2-0.6.11/src/panic.rs | 55 + git2-0.6.11/src/patch.rs | 202 + git2-0.6.11/src/pathspec.rs | 301 + git2-0.6.11/src/proxy_options.rs | 56 + git2-0.6.11/src/reference.rs | 401 + git2-0.6.11/src/reflog.rs | 172 + git2-0.6.11/src/refspec.rs | 89 + git2-0.6.11/src/remote.rs | 753 + git2-0.6.11/src/remote_callbacks.rs | 389 + git2-0.6.11/src/repo.rs | 2412 ++ git2-0.6.11/src/revspec.rs | 26 + git2-0.6.11/src/revwalk.rs | 203 + git2-0.6.11/src/signature.rs | 175 + git2-0.6.11/src/stash.rs | 210 + git2-0.6.11/src/status.rs | 407 + git2-0.6.11/src/string_array.rs | 117 + git2-0.6.11/src/submodule.rs | 344 + git2-0.6.11/src/tag.rs | 191 + git2-0.6.11/src/test.rs | 61 + git2-0.6.11/src/time.rs | 95 + git2-0.6.11/src/transport.rs | 326 + git2-0.6.11/src/tree.rs | 406 + git2-0.6.11/src/treebuilder.rs | 199 + git2-0.6.11/src/util.rs | 152 + git2-curl-0.7.0/.cargo-checksum.json | 1 + git2-curl-0.7.0/Cargo.toml | 30 + git2-curl-0.7.0/src/lib.rs | 255 + git2-curl-0.7.0/tests/all.rs | 68 + glob-0.2.11/.cargo-checksum.json | 1 + glob-0.2.11/.travis.yml | 24 + glob-0.2.11/Cargo.toml | 15 + glob-0.2.11/LICENSE-APACHE | 201 + glob-0.2.11/LICENSE-MIT | 25 + glob-0.2.11/README.md | 24 + glob-0.2.11/src/lib.rs | 1312 + glob-0.2.11/tests/glob-std.rs | 278 + globset-0.2.1/.cargo-checksum.json | 1 + globset-0.2.1/COPYING | 3 + globset-0.2.1/Cargo.toml | 46 + globset-0.2.1/LICENSE-MIT | 21 + globset-0.2.1/README.md | 122 + globset-0.2.1/UNLICENSE | 24 + globset-0.2.1/benches/bench.rs | 121 + globset-0.2.1/src/glob.rs | 1340 + globset-0.2.1/src/lib.rs | 835 + globset-0.2.1/src/pathutil.rs | 178 + hamcrest-0.1.1/.cargo-checksum.json | 1 + hamcrest-0.1.1/.travis.yml | 8 + hamcrest-0.1.1/CHANGELOG.md | 5 + hamcrest-0.1.1/Cargo.toml | 26 + hamcrest-0.1.1/LICENSE-APACHE | 57 + hamcrest-0.1.1/LICENSE-MIT | 5 + hamcrest-0.1.1/README.md | 94 + hamcrest-0.1.1/src/core.rs | 38 + hamcrest-0.1.1/src/lib.rs | 35 + hamcrest-0.1.1/src/matchers/close_to.rs | 85 + hamcrest-0.1.1/src/matchers/equal_to.rs | 53 + hamcrest-0.1.1/src/matchers/existing_path.rs | 117 + hamcrest-0.1.1/src/matchers/is.rs | 57 + hamcrest-0.1.1/src/matchers/mod.rs | 15 + hamcrest-0.1.1/src/matchers/none.rs | 52 + hamcrest-0.1.1/src/matchers/regex.rs | 62 + hamcrest-0.1.1/src/matchers/vecs.rs | 127 + hamcrest-0.1.1/tests/prelude.rs | 16 + hex-0.2.0/.cargo-checksum.json | 1 + hex-0.2.0/.travis.yml | 8 + hex-0.2.0/Cargo.toml | 9 + hex-0.2.0/LICENSE-APACHE | 202 + hex-0.2.0/LICENSE-MIT | 19 + hex-0.2.0/README.md | 17 + hex-0.2.0/rust-hex.sublime-project | 8 + hex-0.2.0/src/lib.rs | 157 + hex-0.2.0/toto.rs | 209 + home-0.3.0/.cargo-checksum.json | 1 + home-0.3.0/Cargo.toml | 34 + home-0.3.0/README.md | 24 + home-0.3.0/src/lib.rs | 302 + idna-0.1.4/.cargo-checksum.json | 1 + idna-0.1.4/Cargo.toml | 27 + idna-0.1.4/LICENSE-APACHE | 201 + idna-0.1.4/LICENSE-MIT | 25 + idna-0.1.4/src/IdnaMappingTable.txt | 8405 ++++++ idna-0.1.4/src/lib.rs | 73 + idna-0.1.4/src/make_uts46_mapping_table.py | 139 + idna-0.1.4/src/punycode.rs | 212 + idna-0.1.4/src/uts46.rs | 415 + idna-0.1.4/src/uts46_mapping_table.rs | 12844 +++++++++ idna-0.1.4/tests/IdnaTest.txt | 7848 ++++++ idna-0.1.4/tests/punycode.rs | 65 + idna-0.1.4/tests/punycode_tests.json | 120 + idna-0.1.4/tests/tests.rs | 21 + idna-0.1.4/tests/unit.rs | 40 + idna-0.1.4/tests/uts46.rs | 124 + ignore-0.2.2/.cargo-checksum.json | 1 + ignore-0.2.2/COPYING | 3 + ignore-0.2.2/Cargo.toml | 57 + ignore-0.2.2/LICENSE-MIT | 21 + ignore-0.2.2/README.md | 66 + ignore-0.2.2/UNLICENSE | 24 + ignore-0.2.2/examples/walk.rs | 92 + ignore-0.2.2/src/dir.rs | 800 + ignore-0.2.2/src/gitignore.rs | 692 + ignore-0.2.2/src/lib.rs | 404 + ignore-0.2.2/src/overrides.rs | 256 + ignore-0.2.2/src/pathutil.rs | 108 + ignore-0.2.2/src/types.rs | 686 + ignore-0.2.2/src/walk.rs | 1565 ++ ...atched_path_or_any_parents_tests.gitignore | 216 + ...gnore_matched_path_or_any_parents_tests.rs | 297 + itoa-0.3.4/.cargo-checksum.json | 1 + itoa-0.3.4/.travis.yml | 17 + itoa-0.3.4/Cargo.toml | 26 + itoa-0.3.4/LICENSE-APACHE | 201 + itoa-0.3.4/LICENSE-MIT | 25 + itoa-0.3.4/README.md | 71 + itoa-0.3.4/benches/bench.rs | 68 + itoa-0.3.4/src/lib.rs | 196 + itoa-0.3.4/src/udiv128.rs | 62 + itoa-0.3.4/tests/test.rs | 43 + jobserver-0.1.9/.appveyor.yml | 18 + jobserver-0.1.9/.cargo-checksum.json | 1 + jobserver-0.1.9/.travis.yml | 25 + jobserver-0.1.9/Cargo.toml | 62 + jobserver-0.1.9/LICENSE-APACHE | 201 + jobserver-0.1.9/LICENSE-MIT | 25 + jobserver-0.1.9/README.md | 41 + jobserver-0.1.9/src/lib.rs | 945 + jobserver-0.1.9/tests/client-of-myself.rs | 60 + jobserver-0.1.9/tests/client.rs | 191 + jobserver-0.1.9/tests/helper.rs | 44 + jobserver-0.1.9/tests/make-as-a-client.rs | 77 + jobserver-0.1.9/tests/server.rs | 145 + kernel32-sys-0.2.2/.cargo-checksum.json | 1 + kernel32-sys-0.2.2/Cargo.toml | 17 + kernel32-sys-0.2.2/README.md | 13 + kernel32-sys-0.2.2/build.rs | 6 + kernel32-sys-0.2.2/src/lib.rs | 2754 ++ lazy_static-0.2.11/.cargo-checksum.json | 1 + lazy_static-0.2.11/.travis.yml | 31 + lazy_static-0.2.11/Cargo.toml | 43 + lazy_static-0.2.11/LICENSE-APACHE | 201 + lazy_static-0.2.11/LICENSE-MIT | 25 + lazy_static-0.2.11/README.md | 69 + lazy_static-0.2.11/appveyor.yml | 59 + lazy_static-0.2.11/src/core_lazy.rs | 33 + lazy_static-0.2.11/src/lazy.rs | 39 + lazy_static-0.2.11/src/lib.rs | 212 + lazy_static-0.2.11/src/nightly_lazy.rs | 43 + .../tests/compile-fail/README.md | 22 + .../incorrect_visibility_restriction.rs | 10 + .../tests/compile-fail/static_is_private.rs | 14 + .../tests/compile-fail/static_is_sized.rs | 11 + .../tests/compile-fail/static_never_used.rs | 10 + lazy_static-0.2.11/tests/compile_tests.rs | 18 + lazy_static-0.2.11/tests/no_std.rs | 21 + lazy_static-0.2.11/tests/test.rs | 164 + lazy_static-1.0.0/.cargo-checksum.json | 1 + lazy_static-1.0.0/.travis.yml | 31 + lazy_static-1.0.0/Cargo.toml | 49 + lazy_static-1.0.0/LICENSE-APACHE | 201 + lazy_static-1.0.0/LICENSE-MIT | 25 + lazy_static-1.0.0/README.md | 69 + lazy_static-1.0.0/appveyor.yml | 59 + lazy_static-1.0.0/src/core_lazy.rs | 34 + lazy_static-1.0.0/src/lazy.rs | 40 + lazy_static-1.0.0/src/lib.rs | 222 + lazy_static-1.0.0/src/nightly_lazy.rs | 44 + .../tests/compile-fail/README.md | 22 + .../incorrect_visibility_restriction.rs | 10 + .../tests/compile-fail/static_is_private.rs | 14 + .../tests/compile-fail/static_is_sized.rs | 11 + .../tests/compile-fail/static_never_used.rs | 10 + lazy_static-1.0.0/tests/compile_tests.rs | 18 + lazy_static-1.0.0/tests/no_std.rs | 21 + lazy_static-1.0.0/tests/test.rs | 164 + libc-0.2.35/.cargo-checksum.json | 1 + libc-0.2.35/.travis.yml | 113 + libc-0.2.35/Cargo.toml | 32 + libc-0.2.35/LICENSE-APACHE | 201 + libc-0.2.35/LICENSE-MIT | 25 + libc-0.2.35/README.md | 159 + libc-0.2.35/appveyor.yml | 27 + libc-0.2.35/ci/README.md | 203 + libc-0.2.35/ci/android-install-ndk.sh | 37 + libc-0.2.35/ci/android-install-sdk.sh | 60 + libc-0.2.35/ci/android-sysimage.sh | 52 + .../docker/aarch64-linux-android/Dockerfile | 45 + .../aarch64-unknown-linux-gnu/Dockerfile | 7 + .../aarch64-unknown-linux-musl/Dockerfile | 27 + .../docker/arm-linux-androideabi/Dockerfile | 45 + .../arm-unknown-linux-gnueabihf/Dockerfile | 7 + .../arm-unknown-linux-musleabihf/Dockerfile | 25 + .../asmjs-unknown-emscripten/Dockerfile | 20 + .../ci/docker/i686-linux-android/Dockerfile | 45 + .../docker/i686-unknown-linux-gnu/Dockerfile | 5 + .../docker/i686-unknown-linux-musl/Dockerfile | 30 + .../docker/mips-unknown-linux-gnu/Dockerfile | 10 + .../docker/mips-unknown-linux-musl/Dockerfile | 17 + .../mips64-unknown-linux-gnuabi64/Dockerfile | 11 + .../Dockerfile | 11 + .../mipsel-unknown-linux-musl/Dockerfile | 17 + .../powerpc-unknown-linux-gnu/Dockerfile | 10 + .../powerpc64-unknown-linux-gnu/Dockerfile | 11 + .../powerpc64le-unknown-linux-gnu/Dockerfile | 11 + .../docker/s390x-unknown-linux-gnu/Dockerfile | 18 + .../sparc64-unknown-linux-gnu/Dockerfile | 19 + .../wasm32-unknown-emscripten/Dockerfile | 21 + .../wasm32-unknown-emscripten/node-wrapper.sh | 15 + .../ci/docker/x86_64-linux-android/Dockerfile | 26 + .../docker/x86_64-rumprun-netbsd/Dockerfile | 10 + .../docker/x86_64-rumprun-netbsd/runtest.rs | 54 + .../docker/x86_64-unknown-freebsd/Dockerfile | 13 + .../x86_64-unknown-linux-gnu/Dockerfile | 5 + .../x86_64-unknown-linux-gnux32/Dockerfile | 5 + .../x86_64-unknown-linux-musl/Dockerfile | 20 + libc-0.2.35/ci/dox.sh | 33 + libc-0.2.35/ci/emscripten-entry.sh | 19 + libc-0.2.35/ci/emscripten.sh | 54 + .../ci/ios/deploy_and_run_on_ios_simulator.rs | 171 + libc-0.2.35/ci/landing-page-footer.html | 3 + libc-0.2.35/ci/landing-page-head.html | 7 + libc-0.2.35/ci/linux-s390x.sh | 18 + libc-0.2.35/ci/linux-sparc64.sh | 17 + libc-0.2.35/ci/run-docker.sh | 36 + libc-0.2.35/ci/run-qemu.sh | 32 + libc-0.2.35/ci/run.sh | 82 + libc-0.2.35/ci/runtest-android.rs | 41 + libc-0.2.35/ci/style.rs | 204 + libc-0.2.35/ci/test-runner-linux | 23 + libc-0.2.35/src/cloudabi/aarch64.rs | 4 + libc-0.2.35/src/cloudabi/mod.rs | 162 + libc-0.2.35/src/cloudabi/x86.rs | 4 + libc-0.2.35/src/cloudabi/x86_64.rs | 4 + libc-0.2.35/src/dox.rs | 151 + libc-0.2.35/src/fuchsia/aarch64.rs | 336 + libc-0.2.35/src/fuchsia/mod.rs | 3920 +++ libc-0.2.35/src/fuchsia/powerpc64.rs | 79 + libc-0.2.35/src/fuchsia/x86_64.rs | 447 + libc-0.2.35/src/lib.rs | 301 + libc-0.2.35/src/macros.rs | 71 + libc-0.2.35/src/redox/mod.rs | 104 + libc-0.2.35/src/redox/net.rs | 110 + libc-0.2.35/src/unix/bsd/apple/b32.rs | 60 + libc-0.2.35/src/unix/bsd/apple/b64.rs | 67 + libc-0.2.35/src/unix/bsd/apple/mod.rs | 2397 ++ .../src/unix/bsd/freebsdlike/dragonfly/mod.rs | 753 + .../unix/bsd/freebsdlike/freebsd/aarch64.rs | 32 + .../src/unix/bsd/freebsdlike/freebsd/mod.rs | 911 + .../src/unix/bsd/freebsdlike/freebsd/x86.rs | 31 + .../unix/bsd/freebsdlike/freebsd/x86_64.rs | 32 + libc-0.2.35/src/unix/bsd/freebsdlike/mod.rs | 1172 + libc-0.2.35/src/unix/bsd/mod.rs | 548 + libc-0.2.35/src/unix/bsd/netbsdlike/mod.rs | 640 + .../src/unix/bsd/netbsdlike/netbsd/mod.rs | 1078 + .../bsd/netbsdlike/netbsd/other/b32/mod.rs | 2 + .../bsd/netbsdlike/netbsd/other/b64/mod.rs | 2 + .../unix/bsd/netbsdlike/netbsd/other/mod.rs | 14 + .../bsd/netbsdlike/openbsdlike/bitrig/mod.rs | 89 + .../bsd/netbsdlike/openbsdlike/bitrig/x86.rs | 2 + .../netbsdlike/openbsdlike/bitrig/x86_64.rs | 2 + .../unix/bsd/netbsdlike/openbsdlike/mod.rs | 750 + .../netbsdlike/openbsdlike/openbsd/aarch64.rs | 3 + .../bsd/netbsdlike/openbsdlike/openbsd/mod.rs | 50 + .../bsd/netbsdlike/openbsdlike/openbsd/x86.rs | 3 + .../netbsdlike/openbsdlike/openbsd/x86_64.rs | 3 + libc-0.2.35/src/unix/haiku/b32.rs | 3 + libc-0.2.35/src/unix/haiku/b64.rs | 3 + libc-0.2.35/src/unix/haiku/mod.rs | 1220 + libc-0.2.35/src/unix/mod.rs | 942 + libc-0.2.35/src/unix/newlib/aarch64/mod.rs | 5 + libc-0.2.35/src/unix/newlib/arm/mod.rs | 5 + libc-0.2.35/src/unix/newlib/mod.rs | 690 + .../src/unix/notbsd/android/b32/arm.rs | 357 + .../src/unix/notbsd/android/b32/mod.rs | 230 + .../src/unix/notbsd/android/b32/x86.rs | 415 + .../src/unix/notbsd/android/b64/aarch64.rs | 325 + .../src/unix/notbsd/android/b64/mod.rs | 192 + .../src/unix/notbsd/android/b64/x86_64.rs | 420 + libc-0.2.35/src/unix/notbsd/android/mod.rs | 1157 + libc-0.2.35/src/unix/notbsd/emscripten.rs | 1667 ++ .../src/unix/notbsd/linux/mips/mips32.rs | 637 + .../src/unix/notbsd/linux/mips/mips64.rs | 579 + libc-0.2.35/src/unix/notbsd/linux/mips/mod.rs | 718 + libc-0.2.35/src/unix/notbsd/linux/mod.rs | 1714 ++ .../src/unix/notbsd/linux/musl/b32/arm.rs | 755 + .../src/unix/notbsd/linux/musl/b32/mips.rs | 773 + .../src/unix/notbsd/linux/musl/b32/mod.rs | 68 + .../src/unix/notbsd/linux/musl/b32/x86.rs | 816 + .../src/unix/notbsd/linux/musl/b64/aarch64.rs | 341 + .../src/unix/notbsd/linux/musl/b64/mod.rs | 392 + .../unix/notbsd/linux/musl/b64/powerpc64.rs | 83 + .../src/unix/notbsd/linux/musl/b64/x86_64.rs | 451 + libc-0.2.35/src/unix/notbsd/linux/musl/mod.rs | 321 + .../src/unix/notbsd/linux/other/b32/arm.rs | 612 + .../src/unix/notbsd/linux/other/b32/mod.rs | 315 + .../unix/notbsd/linux/other/b32/powerpc.rs | 614 + .../src/unix/notbsd/linux/other/b32/x86.rs | 769 + .../unix/notbsd/linux/other/b64/aarch64.rs | 786 + .../src/unix/notbsd/linux/other/b64/mod.rs | 85 + .../unix/notbsd/linux/other/b64/not_x32.rs | 351 + .../unix/notbsd/linux/other/b64/powerpc64.rs | 860 + .../unix/notbsd/linux/other/b64/sparc64.rs | 785 + .../src/unix/notbsd/linux/other/b64/x32.rs | 331 + .../src/unix/notbsd/linux/other/b64/x86_64.rs | 656 + .../src/unix/notbsd/linux/other/mod.rs | 617 + libc-0.2.35/src/unix/notbsd/linux/s390x.rs | 1283 + libc-0.2.35/src/unix/notbsd/mod.rs | 1014 + libc-0.2.35/src/unix/solaris/mod.rs | 1398 + libc-0.2.35/src/unix/uclibc/mips/mips32.rs | 269 + libc-0.2.35/src/unix/uclibc/mips/mips64.rs | 209 + libc-0.2.35/src/unix/uclibc/mips/mod.rs | 476 + libc-0.2.35/src/unix/uclibc/mod.rs | 1903 ++ libc-0.2.35/src/unix/uclibc/x86_64/l4re.rs | 46 + libc-0.2.35/src/unix/uclibc/x86_64/mod.rs | 357 + libc-0.2.35/src/windows.rs | 248 + libgit2-sys-0.6.19/.cargo-checksum.json | 1 + libgit2-sys-0.6.19/Cargo.toml | 54 + libgit2-sys-0.6.19/LICENSE-APACHE | 201 + libgit2-sys-0.6.19/LICENSE-MIT | 25 + libgit2-sys-0.6.19/build.rs | 198 + libgit2-sys-0.6.19/lib.rs | 2737 ++ libssh2-sys-0.2.6/.cargo-checksum.json | 1 + libssh2-sys-0.2.6/Cargo.toml | 24 + libssh2-sys-0.2.6/build.rs | 119 + libssh2-sys-0.2.6/lib.rs | 565 + libz-sys-1.0.18/.cargo-checksum.json | 1 + libz-sys-1.0.18/.travis.yml | 29 + libz-sys-1.0.18/Cargo.toml | 32 + libz-sys-1.0.18/LICENSE-APACHE | 201 + libz-sys-1.0.18/LICENSE-MIT | 25 + libz-sys-1.0.18/README.md | 16 + libz-sys-1.0.18/appveyor.yml | 29 + libz-sys-1.0.18/build.rs | 271 + libz-sys-1.0.18/src/lib.rs | 236 + log-0.3.9/.cargo-checksum.json | 1 + log-0.3.9/.travis.yml | 30 + log-0.3.9/Cargo.toml | 45 + log-0.3.9/LICENSE-APACHE | 201 + log-0.3.9/LICENSE-MIT | 25 + log-0.3.9/README.md | 160 + log-0.3.9/appveyor.yml | 18 + log-0.3.9/src/lib.rs | 1091 + log-0.3.9/src/macros.rs | 155 + log-0.4.1/.cargo-checksum.json | 1 + log-0.4.1/.travis.yml | 20 + log-0.4.1/CHANGELOG.md | 83 + log-0.4.1/Cargo.toml | 59 + log-0.4.1/LICENSE-APACHE | 201 + log-0.4.1/LICENSE-MIT | 25 + log-0.4.1/README.md | 74 + log-0.4.1/appveyor.yml | 19 + log-0.4.1/src/lib.rs | 1339 + log-0.4.1/src/macros.rs | 220 + log-0.4.1/src/serde.rs | 258 + log-0.4.1/tests/filters.rs | 66 + matches-0.1.6/.cargo-checksum.json | 1 + matches-0.1.6/Cargo.toml | 12 + matches-0.1.6/LICENSE | 25 + matches-0.1.6/lib.rs | 130 + memchr-0.1.11/.cargo-checksum.json | 1 + memchr-0.1.11/.travis.yml | 13 + memchr-0.1.11/COPYING | 3 + memchr-0.1.11/Cargo.toml | 21 + memchr-0.1.11/LICENSE-MIT | 21 + memchr-0.1.11/Makefile | 14 + memchr-0.1.11/README.md | 27 + memchr-0.1.11/UNLICENSE | 24 + memchr-0.1.11/appveyor.yml | 19 + memchr-0.1.11/benches/bench.rs | 117 + memchr-0.1.11/ctags.rust | 11 + memchr-0.1.11/session.vim | 1 + memchr-0.1.11/src/lib.rs | 613 + memchr-1.0.2/.cargo-checksum.json | 1 + memchr-1.0.2/.travis.yml | 14 + memchr-1.0.2/COPYING | 3 + memchr-1.0.2/Cargo.toml | 44 + memchr-1.0.2/LICENSE-MIT | 21 + memchr-1.0.2/Makefile | 14 + memchr-1.0.2/README.md | 36 + memchr-1.0.2/UNLICENSE | 24 + memchr-1.0.2/appveyor.yml | 19 + memchr-1.0.2/benches/bench.rs | 117 + memchr-1.0.2/ctags.rust | 11 + memchr-1.0.2/session.vim | 1 + memchr-1.0.2/src/lib.rs | 881 + memchr-2.0.1/.cargo-checksum.json | 1 + memchr-2.0.1/.travis.yml | 14 + memchr-2.0.1/COPYING | 3 + memchr-2.0.1/Cargo.toml | 45 + memchr-2.0.1/LICENSE-MIT | 21 + memchr-2.0.1/Makefile | 14 + memchr-2.0.1/README.md | 36 + memchr-2.0.1/UNLICENSE | 24 + memchr-2.0.1/appveyor.yml | 19 + memchr-2.0.1/benches/bench.rs | 117 + memchr-2.0.1/ctags.rust | 11 + memchr-2.0.1/session.vim | 1 + memchr-2.0.1/src/lib.rs | 1062 + miniz-sys-0.1.10/.cargo-checksum.json | 1 + miniz-sys-0.1.10/Cargo.toml | 31 + miniz-sys-0.1.10/build.rs | 8 + miniz-sys-0.1.10/lib.rs | 77 + miniz-sys-0.1.10/miniz.c | 4986 ++++ num-0.1.41/.cargo-checksum.json | 1 + num-0.1.41/.travis.yml | 31 + num-0.1.41/Cargo.toml | 63 + num-0.1.41/LICENSE-APACHE | 201 + num-0.1.41/LICENSE-MIT | 25 + num-0.1.41/README.md | 32 + num-0.1.41/benches/bigint.rs | 294 + num-0.1.41/benches/shootout-pidigits.rs | 131 + num-0.1.41/bors.toml | 3 + num-0.1.41/ci/deploy.enc | Bin 0 -> 1680 bytes num-0.1.41/ci/deploy.sh | 12 + num-0.1.41/ci/rustup.sh | 18 + num-0.1.41/ci/test_full.sh | 54 + num-0.1.41/doc/favicon.ico | Bin 0 -> 23229 bytes num-0.1.41/doc/index.html | 1 + num-0.1.41/doc/rust-logo-128x128-blk-v2.png | Bin 0 -> 5758 bytes num-0.1.41/src/lib.rs | 111 + num-bigint-0.1.41/.cargo-checksum.json | 1 + num-bigint-0.1.41/Cargo.toml | 45 + num-bigint-0.1.41/LICENSE-APACHE | 201 + num-bigint-0.1.41/LICENSE-MIT | 25 + num-bigint-0.1.41/src/algorithms.rs | 658 + num-bigint-0.1.41/src/bigint.rs | 1767 ++ num-bigint-0.1.41/src/biguint.rs | 2242 ++ num-bigint-0.1.41/src/lib.rs | 154 + num-bigint-0.1.41/src/macros.rs | 316 + num-bigint-0.1.41/src/monty.rs | 127 + num-bigint-0.1.41/src/tests/bigint.rs | 1194 + num-bigint-0.1.41/src/tests/biguint.rs | 1760 ++ num-complex-0.1.41/.cargo-checksum.json | 1 + num-complex-0.1.41/Cargo.toml | 38 + num-complex-0.1.41/LICENSE-APACHE | 201 + num-complex-0.1.41/LICENSE-MIT | 25 + num-complex-0.1.41/src/lib.rs | 1899 ++ num-integer-0.1.35/.cargo-checksum.json | 1 + num-integer-0.1.35/Cargo.toml | 15 + num-integer-0.1.35/LICENSE-APACHE | 201 + num-integer-0.1.35/LICENSE-MIT | 25 + num-integer-0.1.35/src/lib.rs | 988 + num-iter-0.1.34/.cargo-checksum.json | 1 + num-iter-0.1.34/Cargo.toml | 23 + num-iter-0.1.34/LICENSE-APACHE | 201 + num-iter-0.1.34/LICENSE-MIT | 25 + num-iter-0.1.34/src/lib.rs | 378 + num-rational-0.1.40/.cargo-checksum.json | 1 + num-rational-0.1.40/Cargo.toml | 44 + num-rational-0.1.40/LICENSE-APACHE | 201 + num-rational-0.1.40/LICENSE-MIT | 25 + num-rational-0.1.40/src/lib.rs | 1413 + num-traits-0.1.41/.cargo-checksum.json | 1 + num-traits-0.1.41/Cargo.toml | 25 + num-traits-0.1.41/LICENSE-APACHE | 201 + num-traits-0.1.41/LICENSE-MIT | 25 + num-traits-0.1.41/src/bounds.rs | 99 + num-traits-0.1.41/src/cast.rs | 511 + num-traits-0.1.41/src/float.rs | 1344 + num-traits-0.1.41/src/identities.rs | 148 + num-traits-0.1.41/src/int.rs | 376 + num-traits-0.1.41/src/lib.rs | 437 + num-traits-0.1.41/src/ops/checked.rs | 92 + num-traits-0.1.41/src/ops/mod.rs | 3 + num-traits-0.1.41/src/ops/saturating.rs | 28 + num-traits-0.1.41/src/ops/wrapping.rs | 127 + num-traits-0.1.41/src/pow.rs | 73 + num-traits-0.1.41/src/sign.rs | 204 + num_cpus-1.8.0/.appveyor.yml | 16 + num_cpus-1.8.0/.cargo-checksum.json | 1 + num_cpus-1.8.0/.travis.yml | 66 + num_cpus-1.8.0/CHANGELOG.md | 82 + num_cpus-1.8.0/CONTRIBUTING.md | 16 + num_cpus-1.8.0/Cargo.toml | 25 + num_cpus-1.8.0/LICENSE-APACHE | 201 + num_cpus-1.8.0/LICENSE-MIT | 20 + num_cpus-1.8.0/README.md | 28 + num_cpus-1.8.0/src/lib.rs | 414 + openssl-0.9.23/.cargo-checksum.json | 1 + openssl-0.9.23/Cargo.toml | 58 + openssl-0.9.23/LICENSE | 15 + openssl-0.9.23/README.md | 180 + openssl-0.9.23/build.rs | 32 + openssl-0.9.23/examples/mk_certs.rs | 152 + openssl-0.9.23/src/aes.rs | 180 + openssl-0.9.23/src/asn1.rs | 295 + openssl-0.9.23/src/bio.rs | 78 + openssl-0.9.23/src/bn.rs | 1401 + openssl-0.9.23/src/cms.rs | 87 + openssl-0.9.23/src/conf.rs | 52 + openssl-0.9.23/src/crypto.rs | 6 + openssl-0.9.23/src/dh.rs | 160 + openssl-0.9.23/src/dsa.rs | 261 + openssl-0.9.23/src/ec.rs | 883 + openssl-0.9.23/src/ec_key.rs | 4 + openssl-0.9.23/src/error.rs | 247 + openssl-0.9.23/src/ex_data.rs | 26 + openssl-0.9.23/src/hash.rs | 407 + openssl-0.9.23/src/lib.rs | 84 + openssl-0.9.23/src/macros.rs | 248 + openssl-0.9.23/src/memcmp.rs | 92 + openssl-0.9.23/src/nid.rs | 982 + openssl-0.9.23/src/ocsp.rs | 314 + openssl-0.9.23/src/pkcs12.rs | 276 + openssl-0.9.23/src/pkcs5.rs | 570 + openssl-0.9.23/src/pkey.rs | 425 + openssl-0.9.23/src/rand.rs | 52 + openssl-0.9.23/src/rsa.rs | 538 + openssl-0.9.23/src/sha.rs | 388 + openssl-0.9.23/src/sign.rs | 584 + openssl-0.9.23/src/ssl/bio.rs | 279 + openssl-0.9.23/src/ssl/callbacks.rs | 339 + openssl-0.9.23/src/ssl/connector.rs | 599 + openssl-0.9.23/src/ssl/error.rs | 150 + openssl-0.9.23/src/ssl/mod.rs | 2567 ++ openssl-0.9.23/src/ssl/tests/mod.rs | 1416 + openssl-0.9.23/src/ssl/tests/select.rs | 74 + openssl-0.9.23/src/stack.rs | 360 + openssl-0.9.23/src/string.rs | 82 + openssl-0.9.23/src/symm.rs | 1127 + openssl-0.9.23/src/types.rs | 5 + openssl-0.9.23/src/util.rs | 92 + openssl-0.9.23/src/verify.rs | 68 + openssl-0.9.23/src/version.rs | 126 + openssl-0.9.23/src/x509/extension.rs | 672 + openssl-0.9.23/src/x509/mod.rs | 1225 + openssl-0.9.23/src/x509/store.rs | 63 + openssl-0.9.23/src/x509/tests.rs | 407 + openssl-0.9.23/src/x509/verify.rs | 5 + openssl-0.9.23/test/alt_name_cert.pem | 25 + openssl-0.9.23/test/cert.pem | 19 + openssl-0.9.23/test/certs.pem | 40 + openssl-0.9.23/test/dhparams.pem | 8 + openssl-0.9.23/test/dsa-encrypted.pem | 15 + openssl-0.9.23/test/dsa.pem | 12 + openssl-0.9.23/test/dsa.pem.pub | 12 + openssl-0.9.23/test/dsaparam.pem | 9 + openssl-0.9.23/test/identity.p12 | Bin 0 -> 3386 bytes openssl-0.9.23/test/key.der | Bin 0 -> 1193 bytes openssl-0.9.23/test/key.der.pub | Bin 0 -> 294 bytes openssl-0.9.23/test/key.pem | 28 + openssl-0.9.23/test/key.pem.pub | 9 + openssl-0.9.23/test/keystore-empty-chain.p12 | Bin 0 -> 2514 bytes openssl-0.9.23/test/nid_test_cert.pem | 12 + openssl-0.9.23/test/nid_uid_test_cert.pem | 24 + openssl-0.9.23/test/pkcs8.der | Bin 0 -> 1298 bytes openssl-0.9.23/test/root-ca.key | 27 + openssl-0.9.23/test/root-ca.pem | 21 + openssl-0.9.23/test/rsa-encrypted.pem | 30 + openssl-0.9.23/test/rsa.pem | 27 + openssl-0.9.23/test/rsa.pem.pub | 9 + openssl-probe-0.1.2/.cargo-checksum.json | 1 + openssl-probe-0.1.2/Cargo.toml | 21 + openssl-probe-0.1.2/LICENSE-APACHE | 201 + openssl-probe-0.1.2/LICENSE-MIT | 25 + openssl-probe-0.1.2/README.md | 33 + openssl-probe-0.1.2/src/lib.rs | 83 + openssl-sys-0.9.23/.cargo-checksum.json | 1 + openssl-sys-0.9.23/Cargo.toml | 34 + openssl-sys-0.9.23/LICENSE-MIT | 25 + openssl-sys-0.9.23/README.md | 180 + openssl-sys-0.9.23/build.rs | 543 + openssl-sys-0.9.23/src/lib.rs | 2679 ++ openssl-sys-0.9.23/src/libressl/mod.rs | 600 + openssl-sys-0.9.23/src/libressl/v250.rs | 221 + openssl-sys-0.9.23/src/libressl/v25x.rs | 89 + openssl-sys-0.9.23/src/ossl10x.rs | 985 + openssl-sys-0.9.23/src/ossl110.rs | 291 + percent-encoding-1.0.1/.cargo-checksum.json | 1 + percent-encoding-1.0.1/Cargo.toml | 24 + percent-encoding-1.0.1/LICENSE-APACHE | 201 + percent-encoding-1.0.1/LICENSE-MIT | 25 + percent-encoding-1.0.1/lib.rs | 442 + pkg-config-0.3.9/.cargo-checksum.json | 1 + pkg-config-0.3.9/.travis.yml | 23 + pkg-config-0.3.9/Cargo.toml | 16 + pkg-config-0.3.9/LICENSE-APACHE | 201 + pkg-config-0.3.9/LICENSE-MIT | 25 + pkg-config-0.3.9/README.md | 44 + pkg-config-0.3.9/src/lib.rs | 510 + pkg-config-0.3.9/tests/foo.pc | 16 + pkg-config-0.3.9/tests/framework.pc | 16 + pkg-config-0.3.9/tests/test.rs | 99 + quote-0.3.15/.cargo-checksum.json | 1 + quote-0.3.15/Cargo.toml | 10 + quote-0.3.15/LICENSE-APACHE | 201 + quote-0.3.15/LICENSE-MIT | 25 + quote-0.3.15/README.md | 104 + quote-0.3.15/src/ident.rs | 57 + quote-0.3.15/src/lib.rs | 252 + quote-0.3.15/src/to_tokens.rs | 357 + quote-0.3.15/src/tokens.rs | 156 + quote-0.3.15/tests/test.rs | 360 + rand-0.3.20/.cargo-checksum.json | 1 + rand-0.3.20/.travis.yml | 31 + rand-0.3.20/Cargo.toml | 32 + rand-0.3.20/LICENSE-APACHE | 201 + rand-0.3.20/LICENSE-MIT | 25 + rand-0.3.20/README.md | 87 + rand-0.3.20/appveyor.yml | 37 + rand-0.3.20/benches/bench.rs | 97 + .../benches/distributions/exponential.rs | 18 + rand-0.3.20/benches/distributions/gamma.rs | 31 + rand-0.3.20/benches/distributions/mod.rs | 3 + rand-0.3.20/benches/distributions/normal.rs | 18 + rand-0.3.20/src/chacha.rs | 318 + rand-0.3.20/src/distributions/exponential.rs | 124 + rand-0.3.20/src/distributions/gamma.rs | 386 + rand-0.3.20/src/distributions/mod.rs | 401 + rand-0.3.20/src/distributions/normal.rs | 201 + rand-0.3.20/src/distributions/range.rs | 233 + .../src/distributions/ziggurat_tables.rs | 280 + rand-0.3.20/src/isaac.rs | 635 + rand-0.3.20/src/lib.rs | 1295 + rand-0.3.20/src/os.rs | 600 + rand-0.3.20/src/rand_impls.rs | 300 + rand-0.3.20/src/read.rs | 123 + rand-0.3.20/src/reseeding.rs | 229 + redox_syscall-0.1.37/.cargo-checksum.json | 1 + redox_syscall-0.1.37/Cargo.toml | 23 + redox_syscall-0.1.37/LICENSE | 22 + redox_syscall-0.1.37/README.md | 7 + redox_syscall-0.1.37/rust-toolchain | 1 + redox_syscall-0.1.37/src/arch/arm.rs | 73 + redox_syscall-0.1.37/src/arch/x86.rs | 73 + redox_syscall-0.1.37/src/arch/x86_64.rs | 74 + redox_syscall-0.1.37/src/call.rs | 351 + redox_syscall-0.1.37/src/data.rs | 167 + redox_syscall-0.1.37/src/error.rs | 315 + redox_syscall-0.1.37/src/flag.rs | 148 + redox_syscall-0.1.37/src/io/dma.rs | 76 + redox_syscall-0.1.37/src/io/io.rs | 67 + redox_syscall-0.1.37/src/io/mmio.rs | 31 + redox_syscall-0.1.37/src/io/mod.rs | 11 + redox_syscall-0.1.37/src/io/pio.rs | 89 + redox_syscall-0.1.37/src/lib.rs | 47 + redox_syscall-0.1.37/src/number.rs | 73 + redox_syscall-0.1.37/src/scheme.rs | 302 + redox_termios-0.1.1/.cargo-checksum.json | 1 + redox_termios-0.1.1/Cargo.toml | 26 + redox_termios-0.1.1/LICENSE | 21 + redox_termios-0.1.1/README.md | 2 + redox_termios-0.1.1/src/lib.rs | 218 + regex-0.1.80/.cargo-checksum.json | 1 + regex-0.1.80/.travis.yml | 53 + regex-0.1.80/CHANGELOG.md | 128 + regex-0.1.80/Cargo.toml | 93 + regex-0.1.80/HACKING.md | 315 + regex-0.1.80/LICENSE-APACHE | 201 + regex-0.1.80/LICENSE-MIT | 25 + regex-0.1.80/PERFORMANCE.md | 279 + regex-0.1.80/README.md | 241 + regex-0.1.80/appveyor.yml | 17 + regex-0.1.80/examples/regexdna-input.txt | 1671 ++ regex-0.1.80/examples/regexdna-output.txt | 13 + .../examples/shootout-regex-dna-bytes.rs | 66 + .../examples/shootout-regex-dna-cheat.rs | 88 + .../examples/shootout-regex-dna-replace.rs | 19 + .../shootout-regex-dna-single-cheat.rs | 73 + .../examples/shootout-regex-dna-single.rs | 55 + regex-0.1.80/examples/shootout-regex-dna.rs | 66 + regex-0.1.80/run-kcov | 59 + regex-0.1.80/run-shootout-test | 18 + regex-0.1.80/scripts/frequencies.py | 82 + regex-0.1.80/scripts/regex-match-tests.py | 107 + regex-0.1.80/scripts/unicode.py | 305 + regex-0.1.80/src/backtrack.rs | 302 + regex-0.1.80/src/compile.rs | 1089 + regex-0.1.80/src/dfa.rs | 1860 ++ regex-0.1.80/src/error.rs | 77 + regex-0.1.80/src/exec.rs | 1260 + regex-0.1.80/src/expand.rs | 91 + regex-0.1.80/src/freqs.rs | 271 + regex-0.1.80/src/input.rs | 425 + regex-0.1.80/src/lib.rs | 606 + regex-0.1.80/src/literals.rs | 521 + regex-0.1.80/src/pattern.rs | 65 + regex-0.1.80/src/pikevm.rs | 377 + regex-0.1.80/src/prog.rs | 426 + regex-0.1.80/src/re_builder.rs | 154 + regex-0.1.80/src/re_bytes.rs | 1017 + regex-0.1.80/src/re_plugin.rs | 88 + regex-0.1.80/src/re_set.rs | 355 + regex-0.1.80/src/re_trait.rs | 192 + regex-0.1.80/src/re_unicode.rs | 1206 + regex-0.1.80/src/simd_accel/mod.rs | 5 + regex-0.1.80/src/simd_accel/teddy128.rs | 800 + regex-0.1.80/src/simd_fallback/mod.rs | 1 + regex-0.1.80/src/simd_fallback/teddy128.rs | 23 + regex-0.1.80/src/sparse.rs | 78 + regex-0.1.80/src/testdata/LICENSE | 19 + regex-0.1.80/src/testdata/README | 17 + regex-0.1.80/src/testdata/basic.dat | 221 + regex-0.1.80/src/testdata/nullsubexpr.dat | 79 + regex-0.1.80/src/testdata/repetition.dat | 163 + regex-0.1.80/src/utf8.rs | 270 + regex-0.1.80/tests/api.rs | 242 + regex-0.1.80/tests/api_str.rs | 27 + regex-0.1.80/tests/bytes.rs | 55 + regex-0.1.80/tests/crazy.rs | 78 + regex-0.1.80/tests/flags.rs | 11 + regex-0.1.80/tests/fowler.rs | 371 + regex-0.1.80/tests/macros.rs | 138 + regex-0.1.80/tests/macros_bytes.rs | 43 + regex-0.1.80/tests/macros_str.rs | 33 + regex-0.1.80/tests/misc.rs | 21 + regex-0.1.80/tests/multiline.rs | 49 + regex-0.1.80/tests/noparse.rs | 48 + regex-0.1.80/tests/plugin.rs | 26 + regex-0.1.80/tests/regression.rs | 77 + regex-0.1.80/tests/replace.rs | 35 + regex-0.1.80/tests/searcher.rs | 66 + regex-0.1.80/tests/set.rs | 30 + regex-0.1.80/tests/shortest_match.rs | 14 + regex-0.1.80/tests/suffix_reverse.rs | 16 + regex-0.1.80/tests/test_backtrack.rs | 63 + regex-0.1.80/tests/test_backtrack_bytes.rs | 67 + .../tests/test_backtrack_utf8bytes.rs | 64 + regex-0.1.80/tests/test_default.rs | 82 + regex-0.1.80/tests/test_default_bytes.rs | 58 + regex-0.1.80/tests/test_nfa.rs | 59 + regex-0.1.80/tests/test_nfa_bytes.rs | 68 + regex-0.1.80/tests/test_nfa_utf8bytes.rs | 60 + regex-0.1.80/tests/test_plugin.rs | 31 + regex-0.1.80/tests/unicode.rs | 31 + regex-0.1.80/tests/word_boundary.rs | 89 + regex-0.1.80/tests/word_boundary_ascii.rs | 9 + regex-0.1.80/tests/word_boundary_unicode.rs | 8 + regex-0.2.5/.cargo-checksum.json | 1 + regex-0.2.5/.travis.yml | 32 + regex-0.2.5/CHANGELOG.md | 325 + regex-0.2.5/Cargo.toml | 102 + regex-0.2.5/HACKING.md | 330 + regex-0.2.5/LICENSE-APACHE | 201 + regex-0.2.5/LICENSE-MIT | 25 + regex-0.2.5/PERFORMANCE.md | 279 + regex-0.2.5/README.md | 211 + regex-0.2.5/appveyor.yml | 19 + regex-0.2.5/ci/after_success.sh | 34 + regex-0.2.5/ci/run-kcov | 44 + regex-0.2.5/ci/run-shootout-test | 18 + regex-0.2.5/ci/script.sh | 45 + regex-0.2.5/examples/regexdna-input.txt | 1671 ++ regex-0.2.5/examples/regexdna-output.txt | 13 + .../examples/shootout-regex-dna-bytes.rs | 66 + .../examples/shootout-regex-dna-cheat.rs | 88 + .../examples/shootout-regex-dna-replace.rs | 19 + .../shootout-regex-dna-single-cheat.rs | 73 + .../examples/shootout-regex-dna-single.rs | 55 + regex-0.2.5/examples/shootout-regex-dna.rs | 66 + regex-0.2.5/scripts/frequencies.py | 82 + regex-0.2.5/scripts/regex-match-tests.py | 107 + regex-0.2.5/scripts/unicode.py | 305 + regex-0.2.5/src/backtrack.rs | 302 + regex-0.2.5/src/compile.rs | 1157 + regex-0.2.5/src/dfa.rs | 1884 ++ regex-0.2.5/src/error.rs | 63 + regex-0.2.5/src/exec.rs | 1279 + regex-0.2.5/src/expand.rs | 215 + regex-0.2.5/src/freqs.rs | 271 + regex-0.2.5/src/input.rs | 420 + regex-0.2.5/src/lib.rs | 664 + regex-0.2.5/src/literals.rs | 1058 + regex-0.2.5/src/pattern.rs | 62 + regex-0.2.5/src/pikevm.rs | 377 + regex-0.2.5/src/prog.rs | 425 + regex-0.2.5/src/re_builder.rs | 283 + regex-0.2.5/src/re_bytes.rs | 1032 + regex-0.2.5/src/re_set.rs | 411 + regex-0.2.5/src/re_trait.rs | 268 + regex-0.2.5/src/re_unicode.rs | 1076 + regex-0.2.5/src/simd_accel/mod.rs | 5 + regex-0.2.5/src/simd_accel/teddy128.rs | 794 + regex-0.2.5/src/simd_fallback/mod.rs | 1 + regex-0.2.5/src/simd_fallback/teddy128.rs | 23 + regex-0.2.5/src/sparse.rs | 78 + regex-0.2.5/src/testdata/LICENSE | 19 + regex-0.2.5/src/testdata/README | 17 + regex-0.2.5/src/testdata/basic.dat | 221 + regex-0.2.5/src/testdata/nullsubexpr.dat | 79 + regex-0.2.5/src/testdata/repetition.dat | 163 + regex-0.2.5/src/utf8.rs | 290 + regex-0.2.5/tests/api.rs | 182 + regex-0.2.5/tests/api_str.rs | 31 + regex-0.2.5/tests/bytes.rs | 62 + regex-0.2.5/tests/crazy.rs | 92 + regex-0.2.5/tests/flags.rs | 11 + regex-0.2.5/tests/fowler.rs | 371 + regex-0.2.5/tests/macros.rs | 149 + regex-0.2.5/tests/macros_bytes.rs | 38 + regex-0.2.5/tests/macros_str.rs | 35 + regex-0.2.5/tests/misc.rs | 14 + regex-0.2.5/tests/multiline.rs | 49 + regex-0.2.5/tests/noparse.rs | 48 + regex-0.2.5/tests/plugin.rs | 26 + regex-0.2.5/tests/regression.rs | 99 + regex-0.2.5/tests/replace.rs | 44 + regex-0.2.5/tests/searcher.rs | 66 + regex-0.2.5/tests/set.rs | 32 + regex-0.2.5/tests/shortest_match.rs | 14 + regex-0.2.5/tests/suffix_reverse.rs | 16 + regex-0.2.5/tests/test_backtrack.rs | 64 + regex-0.2.5/tests/test_backtrack_bytes.rs | 65 + regex-0.2.5/tests/test_backtrack_utf8bytes.rs | 65 + regex-0.2.5/tests/test_default.rs | 77 + regex-0.2.5/tests/test_default_bytes.rs | 73 + regex-0.2.5/tests/test_nfa.rs | 60 + regex-0.2.5/tests/test_nfa_bytes.rs | 65 + regex-0.2.5/tests/test_nfa_utf8bytes.rs | 61 + regex-0.2.5/tests/unicode.rs | 31 + regex-0.2.5/tests/word_boundary.rs | 89 + regex-0.2.5/tests/word_boundary_ascii.rs | 9 + regex-0.2.5/tests/word_boundary_unicode.rs | 8 + regex-syntax-0.3.9/.cargo-checksum.json | 1 + regex-syntax-0.3.9/Cargo.toml | 16 + regex-syntax-0.3.9/src/lib.rs | 2043 ++ regex-syntax-0.3.9/src/literals.rs | 1502 + regex-syntax-0.3.9/src/parser.rs | 2757 ++ regex-syntax-0.3.9/src/properties.rs | 459 + regex-syntax-0.3.9/src/unicode.rs | 5715 ++++ regex-syntax-0.4.2/.cargo-checksum.json | 1 + regex-syntax-0.4.2/Cargo.toml | 27 + regex-syntax-0.4.2/src/lib.rs | 2223 ++ regex-syntax-0.4.2/src/literals.rs | 1504 + regex-syntax-0.4.2/src/parser.rs | 3311 +++ regex-syntax-0.4.2/src/properties.rs | 482 + regex-syntax-0.4.2/src/unicode.rs | 6018 ++++ rustc-demangle-0.1.5/.cargo-checksum.json | 1 + rustc-demangle-0.1.5/.travis.yml | 20 + rustc-demangle-0.1.5/Cargo.toml | 22 + rustc-demangle-0.1.5/LICENSE-APACHE | 201 + rustc-demangle-0.1.5/LICENSE-MIT | 25 + rustc-demangle-0.1.5/README.md | 15 + rustc-demangle-0.1.5/src/lib.rs | 361 + rustc-serialize-0.3.24/.cargo-checksum.json | 1 + rustc-serialize-0.3.24/.travis.yml | 24 + rustc-serialize-0.3.24/Cargo.toml | 18 + rustc-serialize-0.3.24/LICENSE-APACHE | 201 + rustc-serialize-0.3.24/LICENSE-MIT | 25 + rustc-serialize-0.3.24/README.md | 31 + rustc-serialize-0.3.24/appveyor.yml | 17 + rustc-serialize-0.3.24/benches/base64.rs | 48 + rustc-serialize-0.3.24/benches/hex.rs | 28 + rustc-serialize-0.3.24/benches/json.rs | 84 + rustc-serialize-0.3.24/src/base64.rs | 489 + .../src/collection_impls.rs | 186 + rustc-serialize-0.3.24/src/hex.rs | 221 + rustc-serialize-0.3.24/src/json.rs | 3999 +++ rustc-serialize-0.3.24/src/lib.rs | 79 + rustc-serialize-0.3.24/src/serialize.rs | 1671 ++ same-file-0.1.3/.cargo-checksum.json | 1 + same-file-0.1.3/.travis.yml | 16 + same-file-0.1.3/COPYING | 27 + same-file-0.1.3/Cargo.toml | 20 + same-file-0.1.3/README.md | 45 + same-file-0.1.3/appveyor.yml | 22 + same-file-0.1.3/examples/is_same_file.rs | 7 + same-file-0.1.3/examples/is_stderr.rs | 33 + same-file-0.1.3/src/lib.rs | 304 + same-file-0.1.3/src/unix.rs | 94 + same-file-0.1.3/src/win.rs | 185 + schannel-0.1.9/.cargo-checksum.json | 1 + schannel-0.1.9/Cargo.toml | 42 + schannel-0.1.9/LICENSE.md | 7 + schannel-0.1.9/README.md | 6 + schannel-0.1.9/appveyor.yml | 26 + schannel-0.1.9/build.rs | 6 + schannel-0.1.9/src/cert_chain.rs | 140 + schannel-0.1.9/src/cert_context.rs | 634 + schannel-0.1.9/src/cert_store.rs | 451 + schannel-0.1.9/src/context_buffer.rs | 22 + schannel-0.1.9/src/crypt_key.rs | 16 + schannel-0.1.9/src/crypt_prov.rs | 225 + schannel-0.1.9/src/ctl_context.rs | 183 + schannel-0.1.9/src/key_handle.rs | 5 + schannel-0.1.9/src/lib.rs | 89 + schannel-0.1.9/src/ncrypt_key.rs | 20 + schannel-0.1.9/src/schannel_cred.rs | 261 + schannel-0.1.9/src/security_context.rs | 107 + schannel-0.1.9/src/test.rs | 626 + schannel-0.1.9/src/tls_stream.rs | 877 + schannel-0.1.9/test/cert.der | Bin 0 -> 799 bytes schannel-0.1.9/test/cert.pem | 19 + schannel-0.1.9/test/identity.p12 | Bin 0 -> 3386 bytes schannel-0.1.9/test/key.key | Bin 0 -> 1193 bytes schannel-0.1.9/test/key.pem | 28 + .../test/self-signed.badssl.com.cer | Bin 0 -> 893 bytes scoped-tls-0.1.0/.cargo-checksum.json | 1 + scoped-tls-0.1.0/.travis.yml | 23 + scoped-tls-0.1.0/Cargo.toml | 14 + scoped-tls-0.1.0/LICENSE-APACHE | 201 + scoped-tls-0.1.0/LICENSE-MIT | 25 + scoped-tls-0.1.0/README.md | 23 + scoped-tls-0.1.0/appveyor.yml | 17 + scoped-tls-0.1.0/src/lib.rs | 249 + scopeguard-0.1.2/.cargo-checksum.json | 1 + scopeguard-0.1.2/.travis.yml | 30 + scopeguard-0.1.2/Cargo.toml | 13 + scopeguard-0.1.2/LICENSE-APACHE | 201 + scopeguard-0.1.2/LICENSE-MIT | 25 + scopeguard-0.1.2/README.rst | 47 + scopeguard-0.1.2/src/lib.rs | 75 + secur32-sys-0.2.0/.cargo-checksum.json | 1 + secur32-sys-0.2.0/Cargo.toml | 18 + secur32-sys-0.2.0/README.md | 13 + secur32-sys-0.2.0/build.rs | 6 + secur32-sys-0.2.0/src/lib.rs | 182 + semver-0.8.0/.cargo-checksum.json | 1 + semver-0.8.0/.travis.yml | 18 + semver-0.8.0/Cargo.toml | 45 + semver-0.8.0/LICENSE-APACHE | 201 + semver-0.8.0/LICENSE-MIT | 25 + semver-0.8.0/README.md | 103 + semver-0.8.0/src/lib.rs | 182 + semver-0.8.0/src/version.rs | 759 + semver-0.8.0/src/version_req.rs | 867 + semver-0.8.0/tests/deprecation.rs | 22 + semver-0.8.0/tests/regression.rs | 25 + semver-0.8.0/tests/serde.rs | 90 + semver-parser-0.7.0/.cargo-checksum.json | 1 + semver-parser-0.7.0/Cargo.toml | 11 + semver-parser-0.7.0/LICENSE-APACHE | 201 + semver-parser-0.7.0/LICENSE-MIT | 25 + semver-parser-0.7.0/src/common.rs | 66 + semver-parser-0.7.0/src/lib.rs | 8 + semver-parser-0.7.0/src/range.rs | 696 + semver-parser-0.7.0/src/recognize.rs | 154 + semver-parser-0.7.0/src/version.rs | 365 + serde-1.0.27/.cargo-checksum.json | 1 + serde-1.0.27/Cargo.toml | 44 + serde-1.0.27/LICENSE-APACHE | 201 + serde-1.0.27/LICENSE-MIT | 25 + serde-1.0.27/README.md | 102 + serde-1.0.27/src/de/from_primitive.rs | 116 + serde-1.0.27/src/de/ignored_any.rs | 215 + serde-1.0.27/src/de/impls.rs | 2061 ++ serde-1.0.27/src/de/mod.rs | 2044 ++ serde-1.0.27/src/de/utf8.rs | 54 + serde-1.0.27/src/de/value.rs | 1303 + serde-1.0.27/src/export.rs | 41 + serde-1.0.27/src/lib.rs | 280 + serde-1.0.27/src/macros.rs | 242 + serde-1.0.27/src/private/de.rs | 2064 ++ serde-1.0.27/src/private/macros.rs | 148 + serde-1.0.27/src/private/mod.rs | 12 + serde-1.0.27/src/private/ser.rs | 1030 + serde-1.0.27/src/ser/impls.rs | 690 + serde-1.0.27/src/ser/impossible.rs | 227 + serde-1.0.27/src/ser/mod.rs | 1882 ++ serde_derive-1.0.27/.cargo-checksum.json | 1 + serde_derive-1.0.27/Cargo.toml | 46 + serde_derive-1.0.27/LICENSE-APACHE | 201 + serde_derive-1.0.27/LICENSE-MIT | 25 + serde_derive-1.0.27/README.md | 102 + serde_derive-1.0.27/src/bound.rs | 258 + serde_derive-1.0.27/src/de.rs | 2479 ++ serde_derive-1.0.27/src/fragment.rs | 84 + serde_derive-1.0.27/src/lib.rs | 64 + serde_derive-1.0.27/src/ser.rs | 1003 + .../.cargo-checksum.json | 1 + serde_derive_internals-0.19.0/Cargo.toml | 33 + serde_derive_internals-0.19.0/LICENSE-APACHE | 201 + serde_derive_internals-0.19.0/LICENSE-MIT | 25 + serde_derive_internals-0.19.0/README.md | 102 + serde_derive_internals-0.19.0/src/ast.rs | 158 + serde_derive_internals-0.19.0/src/attr.rs | 1281 + serde_derive_internals-0.19.0/src/case.rs | 186 + serde_derive_internals-0.19.0/src/check.rs | 171 + serde_derive_internals-0.19.0/src/ctxt.rs | 55 + serde_derive_internals-0.19.0/src/lib.rs | 22 + serde_ignored-0.0.4/.cargo-checksum.json | 1 + serde_ignored-0.0.4/.travis.yml | 9 + serde_ignored-0.0.4/Cargo.toml | 16 + serde_ignored-0.0.4/LICENSE-APACHE | 201 + serde_ignored-0.0.4/LICENSE-MIT | 25 + serde_ignored-0.0.4/README.md | 98 + serde_ignored-0.0.4/src/lib.rs | 1104 + serde_json-1.0.9/.cargo-checksum.json | 1 + serde_json-1.0.9/Cargo.toml | 56 + serde_json-1.0.9/LICENSE-APACHE | 201 + serde_json-1.0.9/LICENSE-MIT | 25 + serde_json-1.0.9/README.md | 356 + serde_json-1.0.9/src/de.rs | 2047 ++ serde_json-1.0.9/src/error.rs | 420 + serde_json-1.0.9/src/iter.rs | 78 + serde_json-1.0.9/src/lib.rs | 385 + serde_json-1.0.9/src/macros.rs | 282 + serde_json-1.0.9/src/map.rs | 796 + serde_json-1.0.9/src/number.rs | 388 + serde_json-1.0.9/src/read.rs | 698 + serde_json-1.0.9/src/ser.rs | 1821 ++ serde_json-1.0.9/src/value/de.rs | 909 + serde_json-1.0.9/src/value/from.rs | 268 + serde_json-1.0.9/src/value/index.rs | 286 + serde_json-1.0.9/src/value/mod.rs | 1064 + serde_json-1.0.9/src/value/partial_eq.rs | 103 + serde_json-1.0.9/src/value/ser.rs | 419 + shell-escape-0.1.3/.cargo-checksum.json | 1 + shell-escape-0.1.3/.travis.yml | 7 + shell-escape-0.1.3/Cargo.toml | 10 + shell-escape-0.1.3/LICENSE-APACHE | 201 + shell-escape-0.1.3/LICENSE-MIT | 25 + shell-escape-0.1.3/README.md | 23 + shell-escape-0.1.3/src/lib.rs | 132 + socket2-0.3.0/.appveyor.yml | 16 + socket2-0.3.0/.cargo-checksum.json | 1 + socket2-0.3.0/.travis.yml | 30 + socket2-0.3.0/Cargo.toml | 39 + socket2-0.3.0/LICENSE-APACHE | 201 + socket2-0.3.0/LICENSE-MIT | 25 + socket2-0.3.0/README.md | 23 + socket2-0.3.0/src/lib.rs | 129 + socket2-0.3.0/src/sockaddr.rs | 216 + socket2-0.3.0/src/socket.rs | 892 + socket2-0.3.0/src/sys/unix/mod.rs | 1036 + socket2-0.3.0/src/sys/unix/weak.rs | 60 + socket2-0.3.0/src/sys/windows.rs | 932 + socket2-0.3.0/src/utils.rs | 51 + strsim-0.6.0/.cargo-checksum.json | 1 + strsim-0.6.0/.editorconfig | 13 + strsim-0.6.0/.travis.yml | 11 + strsim-0.6.0/CHANGELOG.md | 103 + strsim-0.6.0/Cargo.toml | 17 + strsim-0.6.0/LICENSE | 22 + strsim-0.6.0/README.md | 95 + strsim-0.6.0/appveyor.yml | 13 + strsim-0.6.0/dev | 14 + strsim-0.6.0/src/lib.rs | 911 + strsim-0.6.0/tests/lib.rs | 89 + syn-0.11.11/.cargo-checksum.json | 1 + syn-0.11.11/Cargo.toml | 30 + syn-0.11.11/LICENSE-APACHE | 201 + syn-0.11.11/LICENSE-MIT | 25 + syn-0.11.11/README.md | 205 + syn-0.11.11/src/aster/generics.rs | 231 + syn-0.11.11/src/aster/ident.rs | 39 + syn-0.11.11/src/aster/invoke.rs | 16 + syn-0.11.11/src/aster/lifetime.rs | 103 + syn-0.11.11/src/aster/mod.rs | 33 + syn-0.11.11/src/aster/path.rs | 327 + syn-0.11.11/src/aster/qpath.rs | 143 + syn-0.11.11/src/aster/ty.rs | 488 + syn-0.11.11/src/aster/ty_param.rs | 262 + syn-0.11.11/src/aster/where_predicate.rs | 259 + syn-0.11.11/src/attr.rs | 305 + syn-0.11.11/src/constant.rs | 180 + syn-0.11.11/src/data.rs | 297 + syn-0.11.11/src/derive.rs | 124 + syn-0.11.11/src/escape.rs | 294 + syn-0.11.11/src/expr.rs | 1721 ++ syn-0.11.11/src/fold.rs | 942 + syn-0.11.11/src/generics.rs | 513 + syn-0.11.11/src/ident.rs | 129 + syn-0.11.11/src/item.rs | 1477 + syn-0.11.11/src/krate.rs | 57 + syn-0.11.11/src/lib.rs | 211 + syn-0.11.11/src/lit.rs | 484 + syn-0.11.11/src/mac.rs | 430 + syn-0.11.11/src/op.rs | 192 + syn-0.11.11/src/ty.rs | 844 + syn-0.11.11/src/visit.rs | 778 + synom-0.11.3/.cargo-checksum.json | 1 + synom-0.11.3/Cargo.toml | 20 + synom-0.11.3/LICENSE-APACHE | 201 + synom-0.11.3/LICENSE-MIT | 25 + synom-0.11.3/README.md | 199 + synom-0.11.3/src/helper.rs | 543 + synom-0.11.3/src/lib.rs | 1225 + synom-0.11.3/src/space.rs | 99 + tar-0.4.14/.cargo-checksum.json | 1 + tar-0.4.14/.travis.yml | 33 + tar-0.4.14/Cargo.toml | 38 + tar-0.4.14/LICENSE-APACHE | 201 + tar-0.4.14/LICENSE-MIT | 25 + tar-0.4.14/README.md | 80 + tar-0.4.14/appveyor.yml | 20 + tar-0.4.14/examples/extract_file.rs | 25 + tar-0.4.14/examples/list.rs | 17 + tar-0.4.14/examples/raw_list.rs | 47 + tar-0.4.14/examples/write.rs | 12 + tar-0.4.14/src/archive.rs | 431 + tar-0.4.14/src/builder.rs | 410 + tar-0.4.14/src/entry.rs | 563 + tar-0.4.14/src/entry_type.rs | 194 + tar-0.4.14/src/error.rs | 40 + tar-0.4.14/src/header.rs | 1343 + tar-0.4.14/src/lib.rs | 71 + tar-0.4.14/src/pax.rs | 83 + tar-0.4.14/tests/all.rs | 803 + tar-0.4.14/tests/archives/directory.tar | Bin 0 -> 10240 bytes tar-0.4.14/tests/archives/duplicate_dirs.tar | Bin 0 -> 2048 bytes tar-0.4.14/tests/archives/empty_filename.tar | Bin 0 -> 512 bytes tar-0.4.14/tests/archives/file_times.tar | Bin 0 -> 1536 bytes tar-0.4.14/tests/archives/link.tar | Bin 0 -> 10240 bytes tar-0.4.14/tests/archives/pax.tar | Bin 0 -> 10240 bytes tar-0.4.14/tests/archives/reading_files.tar | Bin 0 -> 10240 bytes tar-0.4.14/tests/archives/simple.tar | Bin 0 -> 10240 bytes tar-0.4.14/tests/archives/spaces.tar | Bin 0 -> 2048 bytes tar-0.4.14/tests/archives/sparse.tar | Bin 0 -> 10240 bytes tar-0.4.14/tests/archives/xattrs.tar | Bin 0 -> 10240 bytes tar-0.4.14/tests/entry.rs | 249 + tar-0.4.14/tests/header/mod.rs | 213 + tempdir-0.3.5/.cargo-checksum.json | 1 + tempdir-0.3.5/.travis.yml | 24 + tempdir-0.3.5/Cargo.toml | 17 + tempdir-0.3.5/LICENSE-APACHE | 201 + tempdir-0.3.5/LICENSE-MIT | 25 + tempdir-0.3.5/README.md | 53 + tempdir-0.3.5/src/lib.rs | 330 + tempdir-0.3.5/tests/smoke.rs | 229 + termcolor-0.3.3/.cargo-checksum.json | 1 + termcolor-0.3.3/COPYING | 3 + termcolor-0.3.3/Cargo.toml | 29 + termcolor-0.3.3/LICENSE-MIT | 21 + termcolor-0.3.3/README.md | 86 + termcolor-0.3.3/UNLICENSE | 24 + termcolor-0.3.3/src/lib.rs | 1388 + termion-1.5.1/.cargo-checksum.json | 1 + termion-1.5.1/.travis.yml | 14 + termion-1.5.1/Cargo.toml | 17 + termion-1.5.1/LICENSE | 21 + termion-1.5.1/README.md | 181 + termion-1.5.1/examples/alternate_screen.rs | 17 + .../examples/alternate_screen_raw.rs | 40 + termion-1.5.1/examples/async.rs | 39 + termion-1.5.1/examples/click.rs | 35 + termion-1.5.1/examples/color.rs | 10 + termion-1.5.1/examples/commie.rs | 51 + termion-1.5.1/examples/detect_color.rs | 19 + termion-1.5.1/examples/is_tty.rs | 11 + termion-1.5.1/examples/keys.rs | 44 + termion-1.5.1/examples/mouse.rs | 46 + termion-1.5.1/examples/rainbow.rs | 60 + termion-1.5.1/examples/read.rs | 23 + termion-1.5.1/examples/rustc_fun.rs | 24 + termion-1.5.1/examples/simple.rs | 42 + termion-1.5.1/examples/size.rs | 7 + termion-1.5.1/examples/truecolor.rs | 12 + termion-1.5.1/logo.svg | 9 + termion-1.5.1/src/async.rs | 78 + termion-1.5.1/src/clear.rs | 9 + termion-1.5.1/src/color.rs | 242 + termion-1.5.1/src/cursor.rs | 140 + termion-1.5.1/src/event.rs | 351 + termion-1.5.1/src/input.rs | 388 + termion-1.5.1/src/lib.rs | 61 + termion-1.5.1/src/macros.rs | 19 + termion-1.5.1/src/raw.rs | 117 + termion-1.5.1/src/screen.rs | 91 + termion-1.5.1/src/scroll.rs | 23 + termion-1.5.1/src/style.rs | 22 + termion-1.5.1/src/sys/redox/attr.rs | 33 + termion-1.5.1/src/sys/redox/mod.rs | 15 + termion-1.5.1/src/sys/redox/size.rs | 18 + termion-1.5.1/src/sys/redox/tty.rs | 22 + termion-1.5.1/src/sys/unix/attr.rs | 29 + termion-1.5.1/src/sys/unix/mod.rs | 33 + termion-1.5.1/src/sys/unix/size.rs | 48 + termion-1.5.1/src/sys/unix/tty.rs | 17 + thread-id-2.0.0/.appveyor.yml | 30 + thread-id-2.0.0/.cargo-checksum.json | 1 + thread-id-2.0.0/.travis.yml | 9 + thread-id-2.0.0/Cargo.toml | 14 + thread-id-2.0.0/license | 202 + thread-id-2.0.0/readme.md | 47 + thread-id-2.0.0/src/lib.rs | 67 + thread_local-0.2.7/.cargo-checksum.json | 1 + thread_local-0.2.7/.travis.yml | 29 + thread_local-0.2.7/Cargo.toml | 13 + thread_local-0.2.7/LICENSE-APACHE | 201 + thread_local-0.2.7/LICENSE-MIT | 25 + thread_local-0.2.7/README.md | 41 + thread_local-0.2.7/src/lib.rs | 773 + thread_local-0.3.5/.cargo-checksum.json | 1 + thread_local-0.3.5/.travis.yml | 29 + thread_local-0.3.5/Cargo.toml | 29 + thread_local-0.3.5/LICENSE-APACHE | 201 + thread_local-0.3.5/LICENSE-MIT | 25 + thread_local-0.3.5/README.md | 41 + thread_local-0.3.5/benches/thread_local.rs | 18 + thread_local-0.3.5/src/lib.rs | 757 + thread_local-0.3.5/src/thread_id.rs | 61 + toml-0.4.5/.cargo-checksum.json | 1 + toml-0.4.5/.travis.yml | 29 + toml-0.4.5/Cargo.toml | 33 + toml-0.4.5/LICENSE-APACHE | 201 + toml-0.4.5/LICENSE-MIT | 25 + toml-0.4.5/README.md | 31 + toml-0.4.5/examples/decode.rs | 56 + toml-0.4.5/examples/toml2json.rs | 51 + toml-0.4.5/src/datetime.rs | 425 + toml-0.4.5/src/de.rs | 1327 + toml-0.4.5/src/lib.rs | 168 + toml-0.4.5/src/ser.rs | 1714 ++ toml-0.4.5/src/tokens.rs | 620 + toml-0.4.5/src/value.rs | 946 + toml-0.4.5/tests/README.md | 1 + toml-0.4.5/tests/backcompat.rs | 19 + toml-0.4.5/tests/datetime.rs | 58 + toml-0.4.5/tests/display-tricky.rs | 49 + toml-0.4.5/tests/display.rs | 103 + toml-0.4.5/tests/formatting.rs | 55 + toml-0.4.5/tests/invalid-encoder-misc.rs | 14 + .../array-mixed-types-ints-and-floats.json | 15 + toml-0.4.5/tests/invalid-misc.rs | 17 + toml-0.4.5/tests/invalid.rs | 98 + .../array-mixed-types-arrays-and-ints.toml | 1 + .../array-mixed-types-ints-and-floats.toml | 1 + .../array-mixed-types-strings-and-ints.toml | 1 + .../invalid/datetime-malformed-no-leads.toml | 1 + .../invalid/datetime-malformed-no-secs.toml | 1 + .../invalid/datetime-malformed-no-t.toml | 1 + .../datetime-malformed-with-milli.toml | 1 + .../tests/invalid/duplicate-key-table.toml | 5 + toml-0.4.5/tests/invalid/duplicate-keys.toml | 2 + .../tests/invalid/duplicate-tables.toml | 2 + .../tests/invalid/empty-implicit-table.toml | 1 + toml-0.4.5/tests/invalid/empty-table.toml | 1 + .../tests/invalid/float-no-leading-zero.toml | 2 + .../invalid/float-no-trailing-digits.toml | 2 + toml-0.4.5/tests/invalid/key-after-array.toml | 1 + toml-0.4.5/tests/invalid/key-after-table.toml | 1 + toml-0.4.5/tests/invalid/key-empty.toml | 1 + toml-0.4.5/tests/invalid/key-hash.toml | 1 + toml-0.4.5/tests/invalid/key-newline.toml | 2 + .../tests/invalid/key-open-bracket.toml | 1 + .../invalid/key-single-open-bracket.toml | 1 + toml-0.4.5/tests/invalid/key-space.toml | 1 + .../tests/invalid/key-start-bracket.toml | 3 + toml-0.4.5/tests/invalid/key-two-equals.toml | 1 + .../tests/invalid/string-bad-byte-escape.toml | 1 + .../tests/invalid/string-bad-escape.toml | 1 + .../tests/invalid/string-byte-escapes.toml | 1 + toml-0.4.5/tests/invalid/string-no-close.toml | 1 + .../tests/invalid/table-array-implicit.toml | 14 + .../table-array-malformed-bracket.toml | 2 + .../invalid/table-array-malformed-empty.toml | 2 + toml-0.4.5/tests/invalid/table-empty.toml | 1 + .../invalid/table-nested-brackets-close.toml | 2 + .../invalid/table-nested-brackets-open.toml | 2 + .../tests/invalid/table-whitespace.toml | 1 + .../tests/invalid/table-with-pound.toml | 2 + .../invalid/text-after-array-entries.toml | 4 + .../tests/invalid/text-after-integer.toml | 1 + .../tests/invalid/text-after-string.toml | 1 + .../tests/invalid/text-after-table.toml | 1 + .../invalid/text-before-array-separator.toml | 4 + toml-0.4.5/tests/invalid/text-in-array.toml | 5 + toml-0.4.5/tests/parser.rs | 495 + toml-0.4.5/tests/pretty.rs | 308 + toml-0.4.5/tests/serde.rs | 578 + toml-0.4.5/tests/tables-last.rs | 30 + toml-0.4.5/tests/valid.rs | 249 + toml-0.4.5/tests/valid/array-empty.json | 11 + toml-0.4.5/tests/valid/array-empty.toml | 1 + toml-0.4.5/tests/valid/array-nospaces.json | 10 + toml-0.4.5/tests/valid/array-nospaces.toml | 1 + .../tests/valid/arrays-hetergeneous.json | 19 + .../tests/valid/arrays-hetergeneous.toml | 1 + toml-0.4.5/tests/valid/arrays-nested.json | 13 + toml-0.4.5/tests/valid/arrays-nested.toml | 1 + toml-0.4.5/tests/valid/arrays.json | 34 + toml-0.4.5/tests/valid/arrays.toml | 8 + toml-0.4.5/tests/valid/bool.json | 4 + toml-0.4.5/tests/valid/bool.toml | 2 + .../tests/valid/comments-everywhere.json | 12 + .../tests/valid/comments-everywhere.toml | 24 + toml-0.4.5/tests/valid/datetime-truncate.json | 6 + toml-0.4.5/tests/valid/datetime-truncate.toml | 1 + toml-0.4.5/tests/valid/datetime.json | 3 + toml-0.4.5/tests/valid/datetime.toml | 1 + toml-0.4.5/tests/valid/empty.json | 1 + toml-0.4.5/tests/valid/empty.toml | 0 toml-0.4.5/tests/valid/example-bom.toml | 5 + toml-0.4.5/tests/valid/example-v0.3.0.json | 1 + toml-0.4.5/tests/valid/example-v0.3.0.toml | 182 + toml-0.4.5/tests/valid/example-v0.4.0.json | 1 + toml-0.4.5/tests/valid/example-v0.4.0.toml | 235 + toml-0.4.5/tests/valid/example.json | 14 + toml-0.4.5/tests/valid/example.toml | 5 + toml-0.4.5/tests/valid/example2.json | 1 + toml-0.4.5/tests/valid/example2.toml | 47 + toml-0.4.5/tests/valid/float.json | 4 + toml-0.4.5/tests/valid/float.toml | 2 + toml-0.4.5/tests/valid/hard_example.json | 1 + toml-0.4.5/tests/valid/hard_example.toml | 33 + .../valid/implicit-and-explicit-after.json | 10 + .../valid/implicit-and-explicit-after.toml | 5 + .../valid/implicit-and-explicit-before.json | 10 + .../valid/implicit-and-explicit-before.toml | 5 + toml-0.4.5/tests/valid/implicit-groups.json | 9 + toml-0.4.5/tests/valid/implicit-groups.toml | 2 + toml-0.4.5/tests/valid/integer.json | 4 + toml-0.4.5/tests/valid/integer.toml | 2 + .../tests/valid/key-equals-nospace.json | 3 + .../tests/valid/key-equals-nospace.toml | 1 + toml-0.4.5/tests/valid/key-quote-newline.json | 3 + toml-0.4.5/tests/valid/key-quote-newline.toml | 1 + toml-0.4.5/tests/valid/key-space.json | 3 + toml-0.4.5/tests/valid/key-space.toml | 1 + toml-0.4.5/tests/valid/key-special-chars.json | 5 + toml-0.4.5/tests/valid/key-special-chars.toml | 1 + toml-0.4.5/tests/valid/key-with-pound.json | 3 + toml-0.4.5/tests/valid/key-with-pound.toml | 1 + toml-0.4.5/tests/valid/long-float.json | 4 + toml-0.4.5/tests/valid/long-float.toml | 2 + toml-0.4.5/tests/valid/long-integer.json | 4 + toml-0.4.5/tests/valid/long-integer.toml | 2 + toml-0.4.5/tests/valid/multiline-string.json | 30 + toml-0.4.5/tests/valid/multiline-string.toml | 23 + .../tests/valid/raw-multiline-string.json | 14 + .../tests/valid/raw-multiline-string.toml | 9 + toml-0.4.5/tests/valid/raw-string.json | 30 + toml-0.4.5/tests/valid/raw-string.toml | 7 + toml-0.4.5/tests/valid/string-empty.json | 6 + toml-0.4.5/tests/valid/string-empty.toml | 1 + toml-0.4.5/tests/valid/string-escapes.json | 50 + toml-0.4.5/tests/valid/string-escapes.toml | 12 + toml-0.4.5/tests/valid/string-simple.json | 6 + toml-0.4.5/tests/valid/string-simple.toml | 1 + toml-0.4.5/tests/valid/string-with-pound.json | 7 + toml-0.4.5/tests/valid/string-with-pound.toml | 2 + .../tests/valid/table-array-implicit.json | 7 + .../tests/valid/table-array-implicit.toml | 2 + toml-0.4.5/tests/valid/table-array-many.json | 16 + toml-0.4.5/tests/valid/table-array-many.toml | 11 + .../tests/valid/table-array-nest-no-keys.json | 14 + .../tests/valid/table-array-nest-no-keys.toml | 6 + toml-0.4.5/tests/valid/table-array-nest.json | 18 + toml-0.4.5/tests/valid/table-array-nest.toml | 17 + toml-0.4.5/tests/valid/table-array-one.json | 8 + toml-0.4.5/tests/valid/table-array-one.toml | 3 + toml-0.4.5/tests/valid/table-empty.json | 3 + toml-0.4.5/tests/valid/table-empty.toml | 1 + toml-0.4.5/tests/valid/table-multi-empty.json | 5 + toml-0.4.5/tests/valid/table-multi-empty.toml | 5 + toml-0.4.5/tests/valid/table-sub-empty.json | 3 + toml-0.4.5/tests/valid/table-sub-empty.toml | 2 + toml-0.4.5/tests/valid/table-whitespace.json | 3 + toml-0.4.5/tests/valid/table-whitespace.toml | 1 + toml-0.4.5/tests/valid/table-with-pound.json | 5 + toml-0.4.5/tests/valid/table-with-pound.toml | 2 + toml-0.4.5/tests/valid/unicode-escape.json | 5 + toml-0.4.5/tests/valid/unicode-escape.toml | 3 + toml-0.4.5/tests/valid/unicode-literal.json | 3 + toml-0.4.5/tests/valid/unicode-literal.toml | 1 + unicode-bidi-0.3.4/.appveyor.yml | 19 + unicode-bidi-0.3.4/.cargo-checksum.json | 1 + unicode-bidi-0.3.4/.rustfmt.toml | 6 + unicode-bidi-0.3.4/.travis.yml | 38 + unicode-bidi-0.3.4/AUTHORS | 4 + unicode-bidi-0.3.4/COPYRIGHT | 8 + unicode-bidi-0.3.4/Cargo.toml | 49 + unicode-bidi-0.3.4/LICENSE-APACHE | 201 + unicode-bidi-0.3.4/LICENSE-MIT | 25 + unicode-bidi-0.3.4/README.md | 12 + unicode-bidi-0.3.4/src/char_data/mod.rs | 136 + unicode-bidi-0.3.4/src/char_data/tables.rs | 464 + unicode-bidi-0.3.4/src/deprecated.rs | 90 + unicode-bidi-0.3.4/src/explicit.rs | 186 + unicode-bidi-0.3.4/src/format_chars.rs | 42 + unicode-bidi-0.3.4/src/implicit.rs | 228 + unicode-bidi-0.3.4/src/level.rs | 382 + unicode-bidi-0.3.4/src/lib.rs | 890 + unicode-bidi-0.3.4/src/prepare.rs | 366 + .../.cargo-checksum.json | 1 + unicode-normalization-0.1.5/.travis.yml | 20 + unicode-normalization-0.1.5/COPYRIGHT | 7 + unicode-normalization-0.1.5/Cargo.toml | 24 + unicode-normalization-0.1.5/LICENSE-APACHE | 201 + unicode-normalization-0.1.5/LICENSE-MIT | 25 + unicode-normalization-0.1.5/README.md | 32 + .../scripts/unicode.py | 387 + .../scripts/unicode_gen_normtests.py | 81 + unicode-normalization-0.1.5/src/decompose.rs | 145 + unicode-normalization-0.1.5/src/lib.rs | 138 + unicode-normalization-0.1.5/src/normalize.rs | 167 + unicode-normalization-0.1.5/src/recompose.rs | 147 + unicode-normalization-0.1.5/src/tables.rs | 10928 ++++++++ unicode-normalization-0.1.5/src/test.rs | 181 + unicode-normalization-0.1.5/src/testdata.rs | 23216 ++++++++++++++++ unicode-xid-0.0.4/.cargo-checksum.json | 1 + unicode-xid-0.0.4/.travis.yml | 25 + unicode-xid-0.0.4/COPYRIGHT | 7 + unicode-xid-0.0.4/Cargo.toml | 26 + unicode-xid-0.0.4/LICENSE-APACHE | 201 + unicode-xid-0.0.4/LICENSE-MIT | 25 + unicode-xid-0.0.4/README.md | 34 + unicode-xid-0.0.4/scripts/unicode.py | 187 + unicode-xid-0.0.4/src/lib.rs | 87 + unicode-xid-0.0.4/src/tables.rs | 426 + unicode-xid-0.0.4/src/tests.rs | 113 + unreachable-1.0.0/.cargo-checksum.json | 1 + unreachable-1.0.0/.travis.yml | 19 + unreachable-1.0.0/Cargo.toml | 13 + unreachable-1.0.0/LICENSE-APACHE | 202 + unreachable-1.0.0/LICENSE-MIT | 19 + unreachable-1.0.0/README.md | 35 + unreachable-1.0.0/src/lib.rs | 77 + url-1.6.0/.cargo-checksum.json | 1 + url-1.6.0/.travis.yml | 9 + url-1.6.0/Cargo.toml | 74 + url-1.6.0/LICENSE-APACHE | 201 + url-1.6.0/LICENSE-MIT | 25 + url-1.6.0/Makefile | 6 + url-1.6.0/README.md | 10 + url-1.6.0/UPGRADING.md | 263 + url-1.6.0/appveyor.yml | 13 + url-1.6.0/docs/.nojekyll | 0 url-1.6.0/docs/404.html | 3 + url-1.6.0/docs/index.html | 3 + url-1.6.0/github.png | Bin 0 -> 7786 bytes url-1.6.0/rust-url-todo | 14 + url-1.6.0/src/encoding.rs | 146 + url-1.6.0/src/form_urlencoded.rs | 403 + url-1.6.0/src/host.rs | 517 + url-1.6.0/src/lib.rs | 2429 ++ url-1.6.0/src/origin.rs | 130 + url-1.6.0/src/parser.rs | 1182 + url-1.6.0/src/path_segments.rs | 217 + url-1.6.0/src/quirks.rs | 217 + url-1.6.0/src/slicing.rs | 182 + url-1.6.0/tests/data.rs | 199 + url-1.6.0/tests/setters_tests.json | 1148 + url-1.6.0/tests/unit.rs | 490 + url-1.6.0/tests/urltestdata.json | 4465 +++ userenv-sys-0.2.0/.cargo-checksum.json | 1 + userenv-sys-0.2.0/Cargo.toml | 17 + userenv-sys-0.2.0/README.md | 13 + userenv-sys-0.2.0/build.rs | 6 + userenv-sys-0.2.0/src/lib.rs | 95 + utf8-ranges-0.1.3/.cargo-checksum.json | 1 + utf8-ranges-0.1.3/.travis.yml | 9 + utf8-ranges-0.1.3/COPYING | 3 + utf8-ranges-0.1.3/Cargo.toml | 14 + utf8-ranges-0.1.3/LICENSE-MIT | 21 + utf8-ranges-0.1.3/Makefile | 14 + utf8-ranges-0.1.3/README.md | 54 + utf8-ranges-0.1.3/UNLICENSE | 24 + utf8-ranges-0.1.3/benches/bench.rs | 25 + utf8-ranges-0.1.3/ctags.rust | 11 + utf8-ranges-0.1.3/session.vim | 1 + utf8-ranges-0.1.3/src/char_utf8.rs | 36 + utf8-ranges-0.1.3/src/lib.rs | 511 + utf8-ranges-1.0.0/.cargo-checksum.json | 1 + utf8-ranges-1.0.0/.travis.yml | 10 + utf8-ranges-1.0.0/COPYING | 3 + utf8-ranges-1.0.0/Cargo.toml | 14 + utf8-ranges-1.0.0/LICENSE-MIT | 21 + utf8-ranges-1.0.0/Makefile | 14 + utf8-ranges-1.0.0/README.md | 54 + utf8-ranges-1.0.0/UNLICENSE | 24 + utf8-ranges-1.0.0/benches/bench.rs | 25 + utf8-ranges-1.0.0/ctags.rust | 11 + utf8-ranges-1.0.0/session.vim | 1 + utf8-ranges-1.0.0/src/char_utf8.rs | 36 + utf8-ranges-1.0.0/src/lib.rs | 527 + vcpkg-0.2.2/.cargo-checksum.json | 1 + vcpkg-0.2.2/Cargo.toml | 28 + vcpkg-0.2.2/src/lib.rs | 532 + void-1.0.2/.cargo-checksum.json | 1 + void-1.0.2/.travis.yml | 26 + void-1.0.2/Cargo.toml | 15 + void-1.0.2/README.md | 39 + void-1.0.2/src/lib.rs | 121 + walkdir-1.0.7/.cargo-checksum.json | 1 + walkdir-1.0.7/.travis.yml | 13 + walkdir-1.0.7/COPYING | 3 + walkdir-1.0.7/Cargo.toml | 24 + walkdir-1.0.7/LICENSE-MIT | 21 + walkdir-1.0.7/Makefile | 14 + walkdir-1.0.7/README.md | 140 + walkdir-1.0.7/UNLICENSE | 24 + walkdir-1.0.7/appveyor.yml | 23 + walkdir-1.0.7/compare/nftw.c | 25 + walkdir-1.0.7/compare/walk.py | 10 + walkdir-1.0.7/ctags.rust | 11 + walkdir-1.0.7/examples/walkdir.rs | 91 + walkdir-1.0.7/session.vim | 1 + walkdir-1.0.7/src/lib.rs | 1006 + walkdir-1.0.7/src/tests.rs | 742 + winapi-0.2.8/.cargo-checksum.json | 1 + winapi-0.2.8/Cargo.toml | 61 + winapi-0.2.8/LICENSE.md | 21 + winapi-0.2.8/src/activation.rs | 5 + winapi-0.2.8/src/audioclient.rs | 71 + winapi-0.2.8/src/audiosessiontypes.rs | 11 + winapi-0.2.8/src/basetsd.rs | 99 + winapi-0.2.8/src/bcrypt.rs | 356 + winapi-0.2.8/src/cfg.rs | 134 + winapi-0.2.8/src/cfgmgr32.rs | 758 + winapi-0.2.8/src/combaseapi.rs | 17 + winapi-0.2.8/src/commctrl.rs | 3578 +++ winapi-0.2.8/src/commdlg.rs | 583 + winapi-0.2.8/src/corsym.rs | 79 + winapi-0.2.8/src/d2d1.rs | 734 + winapi-0.2.8/src/d2dbasetypes.rs | 61 + winapi-0.2.8/src/d3d10shader.rs | 110 + winapi-0.2.8/src/d3d11.rs | 2665 ++ winapi-0.2.8/src/d3d11shader.rs | 320 + winapi-0.2.8/src/d3d12.rs | 2324 ++ winapi-0.2.8/src/d3d12sdklayers.rs | 1063 + winapi-0.2.8/src/d3d12shader.rs | 320 + winapi-0.2.8/src/d3d9.rs | 713 + winapi-0.2.8/src/d3d9caps.rs | 349 + winapi-0.2.8/src/d3d9types.rs | 1397 + winapi-0.2.8/src/d3dcommon.rs | 753 + winapi-0.2.8/src/d3dcompiler.rs | 74 + winapi-0.2.8/src/dbghelp.rs | 340 + winapi-0.2.8/src/dcommon.rs | 18 + winapi-0.2.8/src/devpropdef.rs | 71 + winapi-0.2.8/src/docobj.rs | 22 + winapi-0.2.8/src/dpapi.rs | 11 + winapi-0.2.8/src/dsgetdc.rs | 113 + winapi-0.2.8/src/dsound.rs | 132 + winapi-0.2.8/src/dsrole.rs | 50 + winapi-0.2.8/src/dwmapi.rs | 9 + winapi-0.2.8/src/dwrite.rs | 1038 + winapi-0.2.8/src/dxgi.rs | 240 + winapi-0.2.8/src/dxgi1_2.rs | 288 + winapi-0.2.8/src/dxgi1_3.rs | 131 + winapi-0.2.8/src/dxgi1_4.rs | 82 + winapi-0.2.8/src/dxgiformat.rs | 124 + winapi-0.2.8/src/dxgitype.rs | 86 + winapi-0.2.8/src/errhandlingapi.rs | 7 + winapi-0.2.8/src/excpt.rs | 14 + winapi-0.2.8/src/fileapi.rs | 152 + winapi-0.2.8/src/gl.rs | 35 + winapi-0.2.8/src/guiddef.rs | 20 + winapi-0.2.8/src/heapapi.rs | 12 + winapi-0.2.8/src/hidclass.rs | 56 + winapi-0.2.8/src/hidpi.rs | 182 + winapi-0.2.8/src/hidsdi.rs | 15 + winapi-0.2.8/src/hidusage.rs | 270 + winapi-0.2.8/src/hstring.rs | 16 + winapi-0.2.8/src/http.rs | 828 + winapi-0.2.8/src/imm.rs | 3 + winapi-0.2.8/src/inaddr.rs | 22 + winapi-0.2.8/src/inspectable.rs | 15 + winapi-0.2.8/src/ksmedia.rs | 18 + winapi-0.2.8/src/lib.rs | 368 + winapi-0.2.8/src/libloaderapi.rs | 23 + winapi-0.2.8/src/lmaccess.rs | 853 + winapi-0.2.8/src/lmcons.rs | 55 + winapi-0.2.8/src/lmdfs.rs | 311 + winapi-0.2.8/src/lmerrlog.rs | 263 + winapi-0.2.8/src/lmjoin.rs | 80 + winapi-0.2.8/src/lsalookup.rs | 69 + winapi-0.2.8/src/macros.rs | 270 + winapi-0.2.8/src/memoryapi.rs | 19 + winapi-0.2.8/src/minschannel.rs | 56 + winapi-0.2.8/src/minwinbase.rs | 253 + winapi-0.2.8/src/minwindef.rs | 89 + winapi-0.2.8/src/mmdeviceapi.rs | 63 + winapi-0.2.8/src/mmreg.rs | 304 + winapi-0.2.8/src/mmsystem.rs | 259 + winapi-0.2.8/src/mscat.rs | 28 + winapi-0.2.8/src/mssip.rs | 103 + winapi-0.2.8/src/nb30.rs | 200 + winapi-0.2.8/src/ncrypt.rs | 9 + winapi-0.2.8/src/ntdef.rs | 7 + winapi-0.2.8/src/ntsecapi.rs | 1589 ++ winapi-0.2.8/src/ntstatus.rs | 2474 ++ winapi-0.2.8/src/oaidl.rs | 590 + winapi-0.2.8/src/objbase.rs | 5 + winapi-0.2.8/src/objidl.rs | 100 + winapi-0.2.8/src/objidlbase.rs | 93 + winapi-0.2.8/src/olectl.rs | 10 + winapi-0.2.8/src/pdh.rs | 52 + winapi-0.2.8/src/playsoundapi.rs | 19 + winapi-0.2.8/src/processsnapshot.rs | 58 + winapi-0.2.8/src/processthreadsapi.rs | 62 + winapi-0.2.8/src/propidl.rs | 10 + winapi-0.2.8/src/propsys.rs | 4 + winapi-0.2.8/src/prsht.rs | 262 + winapi-0.2.8/src/psapi.rs | 166 + winapi-0.2.8/src/qos.rs | 16 + winapi-0.2.8/src/reason.rs | 63 + winapi-0.2.8/src/restrictederrorinfo.rs | 9 + winapi-0.2.8/src/roapi.rs | 13 + winapi-0.2.8/src/roerrorapi.rs | 11 + winapi-0.2.8/src/rpc.rs | 5 + winapi-0.2.8/src/rpcdce.rs | 535 + winapi-0.2.8/src/sapi.rs | 2431 ++ winapi-0.2.8/src/schannel.rs | 333 + winapi-0.2.8/src/servprov.rs | 11 + winapi-0.2.8/src/setupapi.rs | 1301 + winapi-0.2.8/src/shellapi.rs | 62 + winapi-0.2.8/src/shellscalingapi.rs | 19 + winapi-0.2.8/src/shlguid.rs | 2 + winapi-0.2.8/src/shlobj.rs | 94 + winapi-0.2.8/src/shobjidl.rs | 652 + winapi-0.2.8/src/shtypes.rs | 40 + winapi-0.2.8/src/spapidef.rs | 48 + winapi-0.2.8/src/sql.rs | 179 + winapi-0.2.8/src/sqltypes.rs | 130 + winapi-0.2.8/src/sspi.rs | 657 + winapi-0.2.8/src/strmif.rs | 4 + winapi-0.2.8/src/subauth.rs | 198 + winapi-0.2.8/src/synchapi.rs | 14 + winapi-0.2.8/src/sysinfoapi.rs | 46 + winapi-0.2.8/src/threadpoolapi.rs | 7 + winapi-0.2.8/src/timezoneapi.rs | 27 + winapi-0.2.8/src/tlhelp32.rs | 104 + winapi-0.2.8/src/unknwnbase.rs | 29 + winapi-0.2.8/src/urlhist.rs | 56 + winapi-0.2.8/src/urlmon.rs | 6 + winapi-0.2.8/src/usb.rs | 18 + winapi-0.2.8/src/usbspec.rs | 41 + winapi-0.2.8/src/usp10.rs | 201 + winapi-0.2.8/src/vadefs.rs | 7 + winapi-0.2.8/src/vsbackup.rs | 303 + winapi-0.2.8/src/vss.rs | 256 + winapi-0.2.8/src/vsserror.rs | 85 + winapi-0.2.8/src/vswriter.rs | 241 + winapi-0.2.8/src/werapi.rs | 8 + winapi-0.2.8/src/winbase.rs | 552 + winapi-0.2.8/src/wincon.rs | 198 + winapi-0.2.8/src/wincred.rs | 209 + winapi-0.2.8/src/wincrypt.rs | 2206 ++ winapi-0.2.8/src/windef.rs | 57 + winapi-0.2.8/src/windowscodecs.rs | 363 + winapi-0.2.8/src/windowsx.rs | 22 + winapi-0.2.8/src/winerror.rs | 6065 ++++ winapi-0.2.8/src/winevt.rs | 40 + winapi-0.2.8/src/wingdi.rs | 1238 + winapi-0.2.8/src/winhttp.rs | 441 + winapi-0.2.8/src/winioctl.rs | 754 + winapi-0.2.8/src/winnetwk.rs | 275 + winapi-0.2.8/src/winnls.rs | 164 + winapi-0.2.8/src/winnt.rs | 2368 ++ winapi-0.2.8/src/winreg.rs | 41 + winapi-0.2.8/src/winscard.rs | 269 + winapi-0.2.8/src/winsmcrd.rs | 157 + winapi-0.2.8/src/winsock2.rs | 429 + winapi-0.2.8/src/winspool.rs | 29 + winapi-0.2.8/src/winstring.rs | 3 + winapi-0.2.8/src/winsvc.rs | 200 + winapi-0.2.8/src/winusb.rs | 33 + winapi-0.2.8/src/winusbio.rs | 18 + winapi-0.2.8/src/winuser.rs | 2334 ++ winapi-0.2.8/src/ws2def.rs | 279 + winapi-0.2.8/src/ws2ipdef.rs | 42 + winapi-0.2.8/src/ws2spi.rs | 57 + winapi-0.2.8/src/ws2tcpip.rs | 27 + winapi-0.2.8/src/wtypes.rs | 75 + winapi-0.2.8/src/wtypesbase.rs | 37 + winapi-0.2.8/src/xinput.rs | 118 + winapi-0.3.3/.cargo-checksum.json | 1 + winapi-0.3.3/Cargo.toml | 333 + winapi-0.3.3/LICENSE-APACHE | 201 + winapi-0.3.3/LICENSE-MIT | 19 + winapi-0.3.3/README.md | 65 + winapi-0.3.3/build.rs | 392 + winapi-0.3.3/src/lib.rs | 59 + winapi-0.3.3/src/macros.rs | 373 + winapi-0.3.3/src/shared/basetsd.rs | 71 + winapi-0.3.3/src/shared/bcrypt.rs | 1002 + winapi-0.3.3/src/shared/bugcodes.rs | 457 + winapi-0.3.3/src/shared/cderr.rs | 45 + winapi-0.3.3/src/shared/cfg.rs | 139 + winapi-0.3.3/src/shared/d3d9.rs | 1279 + winapi-0.3.3/src/shared/d3d9caps.rs | 367 + winapi-0.3.3/src/shared/d3d9types.rs | 1459 + winapi-0.3.3/src/shared/dcomptypes.rs | 51 + winapi-0.3.3/src/shared/devguid.rs | 179 + winapi-0.3.3/src/shared/devpkey.rs | 402 + winapi-0.3.3/src/shared/devpropdef.rs | 84 + winapi-0.3.3/src/shared/dinputd.rs | 22 + winapi-0.3.3/src/shared/dxgi.rs | 404 + winapi-0.3.3/src/shared/dxgi1_2.rs | 356 + winapi-0.3.3/src/shared/dxgi1_3.rs | 191 + winapi-0.3.3/src/shared/dxgi1_4.rs | 113 + winapi-0.3.3/src/shared/dxgi1_5.rs | 93 + winapi-0.3.3/src/shared/dxgiformat.rs | 128 + winapi-0.3.3/src/shared/dxgitype.rs | 110 + winapi-0.3.3/src/shared/guiddef.rs | 37 + winapi-0.3.3/src/shared/hidclass.rs | 69 + winapi-0.3.3/src/shared/hidpi.rs | 394 + winapi-0.3.3/src/shared/hidsdi.rs | 111 + winapi-0.3.3/src/shared/hidusage.rs | 275 + winapi-0.3.3/src/shared/in6addr.rs | 18 + winapi-0.3.3/src/shared/inaddr.rs | 30 + winapi-0.3.3/src/shared/intsafe.rs | 6 + winapi-0.3.3/src/shared/ksmedia.rs | 23 + winapi-0.3.3/src/shared/ktmtypes.rs | 139 + winapi-0.3.3/src/shared/lmcons.rs | 61 + winapi-0.3.3/src/shared/minwindef.rs | 103 + winapi-0.3.3/src/shared/mmreg.rs | 310 + winapi-0.3.3/src/shared/mod.rs | 63 + winapi-0.3.3/src/shared/mstcpip.rs | 496 + winapi-0.3.3/src/shared/ntddscsi.rs | 823 + winapi-0.3.3/src/shared/ntddser.rs | 18 + winapi-0.3.3/src/shared/ntdef.rs | 1074 + winapi-0.3.3/src/shared/ntstatus.rs | 2575 ++ winapi-0.3.3/src/shared/qos.rs | 21 + winapi-0.3.3/src/shared/rpc.rs | 12 + winapi-0.3.3/src/shared/rpcdce.rs | 566 + winapi-0.3.3/src/shared/rpcndr.rs | 26 + winapi-0.3.3/src/shared/sspi.rs | 1076 + winapi-0.3.3/src/shared/stralign.rs | 41 + winapi-0.3.3/src/shared/usb.rs | 524 + winapi-0.3.3/src/shared/usbiodef.rs | 113 + winapi-0.3.3/src/shared/usbspec.rs | 861 + winapi-0.3.3/src/shared/windef.rs | 117 + winapi-0.3.3/src/shared/windowsx.rs | 18 + winapi-0.3.3/src/shared/winerror.rs | 6114 ++++ winapi-0.3.3/src/shared/winusbio.rs | 39 + winapi-0.3.3/src/shared/wnnc.rs | 80 + winapi-0.3.3/src/shared/ws2def.rs | 561 + winapi-0.3.3/src/shared/ws2ipdef.rs | 79 + winapi-0.3.3/src/shared/wtypes.rs | 100 + winapi-0.3.3/src/shared/wtypesbase.rs | 162 + winapi-0.3.3/src/um/audioclient.rs | 173 + winapi-0.3.3/src/um/audiosessiontypes.rs | 38 + winapi-0.3.3/src/um/avrt.rs | 83 + winapi-0.3.3/src/um/cfgmgr32.rs | 2043 ++ winapi-0.3.3/src/um/cguid.rs | 135 + winapi-0.3.3/src/um/combaseapi.rs | 478 + winapi-0.3.3/src/um/coml2api.rs | 11 + winapi-0.3.3/src/um/commapi.rs | 88 + winapi-0.3.3/src/um/commctrl.rs | 4142 +++ winapi-0.3.3/src/um/commdlg.rs | 715 + winapi-0.3.3/src/um/commoncontrols.rs | 233 + winapi-0.3.3/src/um/consoleapi.rs | 77 + winapi-0.3.3/src/um/corsym.rs | 92 + winapi-0.3.3/src/um/d2d1.rs | 984 + winapi-0.3.3/src/um/d2d1_1.rs | 848 + winapi-0.3.3/src/um/d2d1_2.rs | 68 + winapi-0.3.3/src/um/d2d1effectauthor.rs | 27 + winapi-0.3.3/src/um/d2d1effects.rs | 618 + winapi-0.3.3/src/um/d2d1effects_1.rs | 32 + winapi-0.3.3/src/um/d2d1effects_2.rs | 41 + winapi-0.3.3/src/um/d2dbasetypes.rs | 69 + winapi-0.3.3/src/um/d3d.rs | 62 + winapi-0.3.3/src/um/d3d10.rs | 58 + winapi-0.3.3/src/um/d3d10_1.rs | 12 + winapi-0.3.3/src/um/d3d10_1shader.rs | 8 + winapi-0.3.3/src/um/d3d10effect.rs | 46 + winapi-0.3.3/src/um/d3d10misc.rs | 8 + winapi-0.3.3/src/um/d3d10sdklayers.rs | 14 + winapi-0.3.3/src/um/d3d10shader.rs | 207 + winapi-0.3.3/src/um/d3d11.rs | 3418 +++ winapi-0.3.3/src/um/d3d11_1.rs | 24 + winapi-0.3.3/src/um/d3d11_2.rs | 10 + winapi-0.3.3/src/um/d3d11_3.rs | 24 + winapi-0.3.3/src/um/d3d11_4.rs | 8 + winapi-0.3.3/src/um/d3d11on12.rs | 68 + winapi-0.3.3/src/um/d3d11sdklayers.rs | 20 + winapi-0.3.3/src/um/d3d11shader.rs | 478 + winapi-0.3.3/src/um/d3d12.rs | 2721 ++ winapi-0.3.3/src/um/d3d12sdklayers.rs | 1364 + winapi-0.3.3/src/um/d3d12shader.rs | 348 + winapi-0.3.3/src/um/d3dcommon.rs | 746 + winapi-0.3.3/src/um/d3dcompiler.rs | 275 + winapi-0.3.3/src/um/d3dcsx.rs | 12 + winapi-0.3.3/src/um/d3dx10core.rs | 12 + winapi-0.3.3/src/um/d3dx10math.rs | 8 + winapi-0.3.3/src/um/d3dx10mesh.rs | 20 + winapi-0.3.3/src/um/datetimeapi.rs | 61 + winapi-0.3.3/src/um/davclnt.rs | 105 + winapi-0.3.3/src/um/dbghelp.rs | 633 + winapi-0.3.3/src/um/dcommon.rs | 23 + winapi-0.3.3/src/um/dcomp.rs | 1165 + winapi-0.3.3/src/um/dcompanimation.rs | 39 + winapi-0.3.3/src/um/dde.rs | 21 + winapi-0.3.3/src/um/ddraw.rs | 38 + winapi-0.3.3/src/um/ddrawi.rs | 14 + winapi-0.3.3/src/um/ddrawint.rs | 42 + winapi-0.3.3/src/um/debugapi.rs | 42 + winapi-0.3.3/src/um/dinput.rs | 108 + winapi-0.3.3/src/um/dmksctl.rs | 12 + winapi-0.3.3/src/um/dmusicc.rs | 72 + winapi-0.3.3/src/um/docobj.rs | 38 + winapi-0.3.3/src/um/documenttarget.rs | 25 + winapi-0.3.3/src/um/dpa_dsa.rs | 284 + winapi-0.3.3/src/um/dpapi.rs | 101 + winapi-0.3.3/src/um/dsgetdc.rs | 268 + winapi-0.3.3/src/um/dsound.rs | 345 + winapi-0.3.3/src/um/dsrole.rs | 67 + winapi-0.3.3/src/um/dvp.rs | 26 + winapi-0.3.3/src/um/dwmapi.rs | 72 + winapi-0.3.3/src/um/dwrite.rs | 1478 + winapi-0.3.3/src/um/dwrite_1.rs | 747 + winapi-0.3.3/src/um/dwrite_2.rs | 294 + winapi-0.3.3/src/um/dwrite_3.rs | 465 + winapi-0.3.3/src/um/dxdiag.rs | 12 + winapi-0.3.3/src/um/dxfile.rs | 24 + winapi-0.3.3/src/um/dxgidebug.rs | 20 + winapi-0.3.3/src/um/errhandlingapi.rs | 76 + winapi-0.3.3/src/um/fibersapi.rs | 25 + winapi-0.3.3/src/um/fileapi.rs | 640 + winapi-0.3.3/src/um/gl/gl.rs | 53 + winapi-0.3.3/src/um/gl/mod.rs | 8 + winapi-0.3.3/src/um/handleapi.rs | 37 + winapi-0.3.3/src/um/heapapi.rs | 93 + winapi-0.3.3/src/um/http.rs | 1073 + winapi-0.3.3/src/um/imm.rs | 8 + winapi-0.3.3/src/um/interlockedapi.rs | 32 + winapi-0.3.3/src/um/ioapiset.rs | 72 + winapi-0.3.3/src/um/jobapi.rs | 16 + winapi-0.3.3/src/um/jobapi2.rs | 64 + winapi-0.3.3/src/um/knownfolders.rs | 288 + winapi-0.3.3/src/um/ktmw32.rs | 64 + winapi-0.3.3/src/um/libloaderapi.rs | 237 + winapi-0.3.3/src/um/lmaccess.rs | 1215 + winapi-0.3.3/src/um/lmalert.rs | 76 + winapi-0.3.3/src/um/lmapibuf.rs | 31 + winapi-0.3.3/src/um/lmat.rs | 63 + winapi-0.3.3/src/um/lmdfs.rs | 484 + winapi-0.3.3/src/um/lmerrlog.rs | 269 + winapi-0.3.3/src/um/lmjoin.rs | 233 + winapi-0.3.3/src/um/lmmsg.rs | 57 + winapi-0.3.3/src/um/lmremutl.rs | 62 + winapi-0.3.3/src/um/lmrepl.rs | 201 + winapi-0.3.3/src/um/lmserver.rs | 1256 + winapi-0.3.3/src/um/lmshare.rs | 380 + winapi-0.3.3/src/um/lmstats.rs | 86 + winapi-0.3.3/src/um/lmsvc.rs | 181 + winapi-0.3.3/src/um/lmuse.rs | 102 + winapi-0.3.3/src/um/lmwksta.rs | 422 + winapi-0.3.3/src/um/lsalookup.rs | 76 + winapi-0.3.3/src/um/memoryapi.rs | 391 + winapi-0.3.3/src/um/minschannel.rs | 59 + winapi-0.3.3/src/um/minwinbase.rs | 334 + winapi-0.3.3/src/um/mmdeviceapi.rs | 227 + winapi-0.3.3/src/um/mmeapi.rs | 337 + winapi-0.3.3/src/um/mmsystem.rs | 267 + winapi-0.3.3/src/um/mod.rs | 229 + winapi-0.3.3/src/um/msaatext.rs | 60 + winapi-0.3.3/src/um/mscat.rs | 37 + winapi-0.3.3/src/um/mssip.rs | 256 + winapi-0.3.3/src/um/namedpipeapi.rs | 91 + winapi-0.3.3/src/um/namespaceapi.rs | 37 + winapi-0.3.3/src/um/nb30.rs | 215 + winapi-0.3.3/src/um/ncrypt.rs | 18 + winapi-0.3.3/src/um/ntsecapi.rs | 1658 ++ winapi-0.3.3/src/um/oaidl.rs | 787 + winapi-0.3.3/src/um/objbase.rs | 65 + winapi-0.3.3/src/um/objidl.rs | 282 + winapi-0.3.3/src/um/objidlbase.rs | 957 + winapi-0.3.3/src/um/ocidl.rs | 62 + winapi-0.3.3/src/um/oleauto.rs | 812 + winapi-0.3.3/src/um/olectl.rs | 15 + winapi-0.3.3/src/um/pdh.rs | 807 + winapi-0.3.3/src/um/playsoundapi.rs | 47 + winapi-0.3.3/src/um/powerbase.rs | 36 + winapi-0.3.3/src/um/powersetting.rs | 61 + winapi-0.3.3/src/um/powrprof.rs | 551 + winapi-0.3.3/src/um/processenv.rs | 99 + winapi-0.3.3/src/um/processsnapshot.rs | 121 + winapi-0.3.3/src/um/processthreadsapi.rs | 424 + winapi-0.3.3/src/um/processtopologyapi.rs | 25 + winapi-0.3.3/src/um/profileapi.rs | 17 + winapi-0.3.3/src/um/propidl.rs | 16 + winapi-0.3.3/src/um/propkeydef.rs | 14 + winapi-0.3.3/src/um/propsys.rs | 48 + winapi-0.3.3/src/um/prsht.rs | 362 + winapi-0.3.3/src/um/psapi.rs | 353 + winapi-0.3.3/src/um/realtimeapiset.rs | 31 + winapi-0.3.3/src/um/reason.rs | 63 + winapi-0.3.3/src/um/restrictederrorinfo.rs | 25 + winapi-0.3.3/src/um/rmxfguid.rs | 68 + winapi-0.3.3/src/um/sapi.rs | 1389 + winapi-0.3.3/src/um/sapi51.rs | 3728 +++ winapi-0.3.3/src/um/sapi53.rs | 1824 ++ winapi-0.3.3/src/um/sapiddk.rs | 239 + winapi-0.3.3/src/um/sapiddk51.rs | 648 + winapi-0.3.3/src/um/schannel.rs | 340 + winapi-0.3.3/src/um/securityappcontainer.rs | 17 + winapi-0.3.3/src/um/securitybaseapi.rs | 172 + winapi-0.3.3/src/um/servprov.rs | 24 + winapi-0.3.3/src/um/setupapi.rs | 3573 +++ winapi-0.3.3/src/um/shellapi.rs | 924 + winapi-0.3.3/src/um/shellscalingapi.rs | 45 + winapi-0.3.3/src/um/shlobj.rs | 261 + winapi-0.3.3/src/um/shobjidl.rs | 384 + winapi-0.3.3/src/um/shobjidl_core.rs | 73 + winapi-0.3.3/src/um/shtypes.rs | 47 + winapi-0.3.3/src/um/spapidef.rs | 54 + winapi-0.3.3/src/um/sporder.rs | 42 + winapi-0.3.3/src/um/sql.rs | 109 + winapi-0.3.3/src/um/sqlext.rs | 96 + winapi-0.3.3/src/um/sqltypes.rs | 143 + winapi-0.3.3/src/um/sqlucode.rs | 107 + winapi-0.3.3/src/um/sspi.rs | 8 + winapi-0.3.3/src/um/stringapiset.rs | 76 + winapi-0.3.3/src/um/strmif.rs | 8 + winapi-0.3.3/src/um/subauth.rs | 207 + winapi-0.3.3/src/um/synchapi.rs | 350 + winapi-0.3.3/src/um/sysinfoapi.rs | 218 + winapi-0.3.3/src/um/systemtopologyapi.rs | 22 + winapi-0.3.3/src/um/textstor.rs | 12 + winapi-0.3.3/src/um/threadpoolapiset.rs | 172 + winapi-0.3.3/src/um/threadpoollegacyapiset.rs | 45 + winapi-0.3.3/src/um/timeapi.rs | 21 + winapi-0.3.3/src/um/timezoneapi.rs | 90 + winapi-0.3.3/src/um/tlhelp32.rs | 195 + winapi-0.3.3/src/um/unknwnbase.rs | 44 + winapi-0.3.3/src/um/urlhist.rs | 102 + winapi-0.3.3/src/um/urlmon.rs | 22 + winapi-0.3.3/src/um/userenv.rs | 135 + winapi-0.3.3/src/um/usp10.rs | 563 + winapi-0.3.3/src/um/utilapiset.rs | 26 + winapi-0.3.3/src/um/vsbackup.rs | 539 + winapi-0.3.3/src/um/vss.rs | 291 + winapi-0.3.3/src/um/vsserror.rs | 90 + winapi-0.3.3/src/um/vswriter.rs | 414 + winapi-0.3.3/src/um/werapi.rs | 46 + winapi-0.3.3/src/um/winbase.rs | 2678 ++ winapi-0.3.3/src/um/wincodec.rs | 1865 ++ winapi-0.3.3/src/um/wincodecsdk.rs | 565 + winapi-0.3.3/src/um/wincon.rs | 540 + winapi-0.3.3/src/um/wincred.rs | 424 + winapi-0.3.3/src/um/wincrypt.rs | 7365 +++++ winapi-0.3.3/src/um/windowsceip.rs | 10 + winapi-0.3.3/src/um/winevt.rs | 544 + winapi-0.3.3/src/um/wingdi.rs | 5585 ++++ winapi-0.3.3/src/um/winhttp.rs | 659 + winapi-0.3.3/src/um/wininet.rs | 2365 ++ winapi-0.3.3/src/um/winineti.rs | 143 + winapi-0.3.3/src/um/winioctl.rs | 846 + winapi-0.3.3/src/um/winnetwk.rs | 447 + winapi-0.3.3/src/um/winnls.rs | 818 + winapi-0.3.3/src/um/winnt.rs | 8380 ++++++ winapi-0.3.3/src/um/winreg.rs | 471 + winapi-0.3.3/src/um/winscard.rs | 710 + winapi-0.3.3/src/um/winsmcrd.rs | 167 + winapi-0.3.3/src/um/winsock2.rs | 1451 + winapi-0.3.3/src/um/winspool.rs | 2434 ++ winapi-0.3.3/src/um/winsvc.rs | 367 + winapi-0.3.3/src/um/winusb.rs | 226 + winapi-0.3.3/src/um/winuser.rs | 6784 +++++ winapi-0.3.3/src/um/winver.rs | 54 + winapi-0.3.3/src/um/wow64apiset.rs | 28 + winapi-0.3.3/src/um/ws2spi.rs | 910 + winapi-0.3.3/src/um/ws2tcpip.rs | 347 + winapi-0.3.3/src/um/xinput.rs | 166 + winapi-0.3.3/src/vc/excpt.rs | 19 + winapi-0.3.3/src/vc/limits.rs | 8 + winapi-0.3.3/src/vc/mod.rs | 11 + winapi-0.3.3/src/vc/vadefs.rs | 9 + winapi-0.3.3/src/vc/vcruntime.rs | 10 + winapi-0.3.3/src/winrt/activation.rs | 14 + winapi-0.3.3/src/winrt/hstring.rs | 26 + winapi-0.3.3/src/winrt/inspectable.rs | 30 + winapi-0.3.3/src/winrt/mod.rs | 13 + winapi-0.3.3/src/winrt/roapi.rs | 61 + winapi-0.3.3/src/winrt/robuffer.rs | 13 + winapi-0.3.3/src/winrt/roerrorapi.rs | 104 + winapi-0.3.3/src/winrt/winstring.rs | 151 + winapi-build-0.1.1/.cargo-checksum.json | 1 + winapi-build-0.1.1/Cargo.toml | 11 + winapi-build-0.1.1/src/lib.rs | 14 + .../.cargo-checksum.json | 1 + winapi-i686-pc-windows-gnu-0.3.2/Cargo.toml | 22 + winapi-i686-pc-windows-gnu-0.3.2/build.rs | 14 + winapi-i686-pc-windows-gnu-0.3.2/src/lib.rs | 7 + .../.cargo-checksum.json | 1 + winapi-x86_64-pc-windows-gnu-0.3.2/Cargo.toml | 22 + winapi-x86_64-pc-windows-gnu-0.3.2/build.rs | 14 + winapi-x86_64-pc-windows-gnu-0.3.2/src/lib.rs | 7 + wincolor-0.1.4/.cargo-checksum.json | 1 + wincolor-0.1.4/COPYING | 3 + wincolor-0.1.4/Cargo.toml | 32 + wincolor-0.1.4/LICENSE-MIT | 21 + wincolor-0.1.4/README.md | 44 + wincolor-0.1.4/UNLICENSE | 24 + wincolor-0.1.4/src/lib.rs | 32 + wincolor-0.1.4/src/win.rs | 230 + 2555 files changed, 717032 insertions(+) create mode 100644 advapi32-sys-0.2.0/.cargo-checksum.json create mode 100644 advapi32-sys-0.2.0/Cargo.toml create mode 100644 advapi32-sys-0.2.0/README.md create mode 100644 advapi32-sys-0.2.0/build.rs create mode 100644 advapi32-sys-0.2.0/src/lib.rs create mode 100644 aho-corasick-0.5.3/.cargo-checksum.json create mode 100644 aho-corasick-0.5.3/.travis.yml create mode 100644 aho-corasick-0.5.3/COPYING create mode 100644 aho-corasick-0.5.3/Cargo.toml create mode 100644 aho-corasick-0.5.3/LICENSE-MIT create mode 100644 aho-corasick-0.5.3/Makefile create mode 100644 aho-corasick-0.5.3/README.md create mode 100644 aho-corasick-0.5.3/UNLICENSE create mode 100644 aho-corasick-0.5.3/benches/bench.rs create mode 100644 aho-corasick-0.5.3/benches/random.txt create mode 100644 aho-corasick-0.5.3/benches/sherlock.txt create mode 100644 aho-corasick-0.5.3/ctags.rust create mode 100644 aho-corasick-0.5.3/examples/dict-search.rs create mode 100644 aho-corasick-0.5.3/session.vim create mode 100644 aho-corasick-0.5.3/src/autiter.rs create mode 100644 aho-corasick-0.5.3/src/full.rs create mode 100644 aho-corasick-0.5.3/src/lib.rs create mode 100644 aho-corasick-0.5.3/src/main.rs create mode 100644 aho-corasick-0.6.4/.cargo-checksum.json create mode 100644 aho-corasick-0.6.4/.travis.yml create mode 100644 aho-corasick-0.6.4/COPYING create mode 100644 aho-corasick-0.6.4/Cargo.toml create mode 100644 aho-corasick-0.6.4/LICENSE-MIT create mode 100644 aho-corasick-0.6.4/Makefile create mode 100644 aho-corasick-0.6.4/README.md create mode 100644 aho-corasick-0.6.4/UNLICENSE create mode 100644 aho-corasick-0.6.4/benches/bench.rs create mode 100644 aho-corasick-0.6.4/benches/random.txt create mode 100644 aho-corasick-0.6.4/ctags.rust create mode 100644 aho-corasick-0.6.4/examples/dict-search.rs create mode 100644 aho-corasick-0.6.4/session.vim create mode 100644 aho-corasick-0.6.4/src/autiter.rs create mode 100644 aho-corasick-0.6.4/src/full.rs create mode 100644 aho-corasick-0.6.4/src/lib.rs create mode 100644 aho-corasick-0.6.4/src/main.rs create mode 100644 atty-0.2.6/.cargo-checksum.json create mode 100644 atty-0.2.6/.travis.yml create mode 100644 atty-0.2.6/CHANGELOG.md create mode 100644 atty-0.2.6/Cargo.toml create mode 100644 atty-0.2.6/LICENSE create mode 100644 atty-0.2.6/README.md create mode 100644 atty-0.2.6/appveyor.yml create mode 100644 atty-0.2.6/examples/atty.rs create mode 100644 atty-0.2.6/rustfmt.toml create mode 100644 atty-0.2.6/src/lib.rs create mode 100644 backtrace-0.3.5/.cargo-checksum.json create mode 100644 backtrace-0.3.5/.travis.yml create mode 100644 backtrace-0.3.5/Cargo.toml create mode 100644 backtrace-0.3.5/LICENSE-APACHE create mode 100644 backtrace-0.3.5/LICENSE-MIT create mode 100644 backtrace-0.3.5/README.md create mode 100644 backtrace-0.3.5/appveyor.yml create mode 100644 backtrace-0.3.5/examples/backtrace.rs create mode 100644 backtrace-0.3.5/examples/raw.rs create mode 100644 backtrace-0.3.5/src/backtrace/dbghelp.rs create mode 100644 backtrace-0.3.5/src/backtrace/libunwind.rs create mode 100644 backtrace-0.3.5/src/backtrace/mod.rs create mode 100644 backtrace-0.3.5/src/backtrace/noop.rs create mode 100644 backtrace-0.3.5/src/backtrace/unix_backtrace.rs create mode 100644 backtrace-0.3.5/src/capture.rs create mode 100644 backtrace-0.3.5/src/dylib.rs create mode 100644 backtrace-0.3.5/src/lib.rs create mode 100644 backtrace-0.3.5/src/symbolize/coresymbolication.rs create mode 100644 backtrace-0.3.5/src/symbolize/dbghelp.rs create mode 100644 backtrace-0.3.5/src/symbolize/dladdr.rs create mode 100644 backtrace-0.3.5/src/symbolize/gimli.rs create mode 100644 backtrace-0.3.5/src/symbolize/libbacktrace.rs create mode 100644 backtrace-0.3.5/src/symbolize/mod.rs create mode 100644 backtrace-0.3.5/src/symbolize/noop.rs create mode 100644 backtrace-0.3.5/tests/long_fn_name.rs create mode 100644 backtrace-0.3.5/tests/smoke.rs create mode 100644 backtrace-sys-0.1.16/.cargo-checksum.json create mode 100644 backtrace-sys-0.1.16/Cargo.toml create mode 100644 backtrace-sys-0.1.16/build.rs create mode 100644 backtrace-sys-0.1.16/src/lib.rs create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/ChangeLog create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/ChangeLog.jit create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/Makefile.am create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/Makefile.in create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/README create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/aclocal.m4 create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/alloc.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/ansidecl.h create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/atomic.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/backtrace-supported.h.in create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/backtrace.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/backtrace.h create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/btest.c create mode 100755 backtrace-sys-0.1.16/src/libbacktrace/config.guess create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/config.h.in create mode 100755 backtrace-sys-0.1.16/src/libbacktrace/config.sub create mode 100755 backtrace-sys-0.1.16/src/libbacktrace/configure create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/configure.ac create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/dwarf.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/dwarf2.def create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/dwarf2.h create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/elf.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/fileline.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/filenames.h create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/filetype.awk create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/hashtab.h create mode 100755 backtrace-sys-0.1.16/src/libbacktrace/install-sh create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/internal.h create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/ltmain.sh create mode 100755 backtrace-sys-0.1.16/src/libbacktrace/missing create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/mmap.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/mmapio.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/nounwind.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/pecoff.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/posix.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/print.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/read.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/simple.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/sort.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/state.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/stest.c create mode 100644 backtrace-sys-0.1.16/src/libbacktrace/unknown.c create mode 100644 backtrace-sys-0.1.16/symbol-map create mode 100644 bitflags-0.9.1/.cargo-checksum.json create mode 100644 bitflags-0.9.1/.travis.yml create mode 100644 bitflags-0.9.1/Cargo.toml create mode 100644 bitflags-0.9.1/LICENSE-APACHE create mode 100644 bitflags-0.9.1/LICENSE-MIT create mode 100644 bitflags-0.9.1/README.md create mode 100644 bitflags-0.9.1/src/example_generated.rs create mode 100644 bitflags-0.9.1/src/lib.rs create mode 100644 bitflags-0.9.1/tests/conflicting_trait_impls.rs create mode 100644 bitflags-0.9.1/tests/external.rs create mode 100644 bitflags-0.9.1/tests/external_no_std.rs create mode 100644 bitflags-0.9.1/tests/i128_bitflags.rs create mode 100644 bitflags-1.0.1/.cargo-checksum.json create mode 100644 bitflags-1.0.1/.travis.yml create mode 100644 bitflags-1.0.1/CHANGELOG.md create mode 100644 bitflags-1.0.1/Cargo.toml create mode 100644 bitflags-1.0.1/LICENSE-APACHE create mode 100644 bitflags-1.0.1/LICENSE-MIT create mode 100644 bitflags-1.0.1/README.md create mode 100644 bitflags-1.0.1/src/example_generated.rs create mode 100644 bitflags-1.0.1/src/lib.rs create mode 100644 bufstream-0.1.3/.cargo-checksum.json create mode 100644 bufstream-0.1.3/.travis.yml create mode 100644 bufstream-0.1.3/Cargo.toml create mode 100644 bufstream-0.1.3/LICENSE-APACHE create mode 100644 bufstream-0.1.3/LICENSE-MIT create mode 100644 bufstream-0.1.3/README.md create mode 100644 bufstream-0.1.3/src/lib.rs create mode 100644 cc-1.0.4/.cargo-checksum.json create mode 100644 cc-1.0.4/.travis.yml create mode 100644 cc-1.0.4/Cargo.toml create mode 100644 cc-1.0.4/LICENSE-APACHE create mode 100644 cc-1.0.4/LICENSE-MIT create mode 100644 cc-1.0.4/README.md create mode 100644 cc-1.0.4/appveyor.yml create mode 100644 cc-1.0.4/src/bin/gcc-shim.rs create mode 100644 cc-1.0.4/src/com.rs create mode 100644 cc-1.0.4/src/lib.rs create mode 100644 cc-1.0.4/src/registry.rs create mode 100644 cc-1.0.4/src/setup_config.rs create mode 100644 cc-1.0.4/src/winapi.rs create mode 100644 cc-1.0.4/src/windows_registry.rs create mode 100644 cc-1.0.4/tests/cc_env.rs create mode 100644 cc-1.0.4/tests/support/mod.rs create mode 100644 cc-1.0.4/tests/test.rs create mode 100644 cfg-if-0.1.2/.cargo-checksum.json create mode 100644 cfg-if-0.1.2/.travis.yml create mode 100644 cfg-if-0.1.2/Cargo.toml create mode 100644 cfg-if-0.1.2/LICENSE-APACHE create mode 100644 cfg-if-0.1.2/LICENSE-MIT create mode 100644 cfg-if-0.1.2/README.md create mode 100644 cfg-if-0.1.2/src/lib.rs create mode 100644 cfg-if-0.1.2/tests/xcrate.rs create mode 100644 cmake-0.1.29/.cargo-checksum.json create mode 100644 cmake-0.1.29/.travis.yml create mode 100644 cmake-0.1.29/Cargo.toml create mode 100644 cmake-0.1.29/LICENSE-APACHE create mode 100644 cmake-0.1.29/LICENSE-MIT create mode 100644 cmake-0.1.29/README.md create mode 100644 cmake-0.1.29/src/lib.rs create mode 100644 commoncrypto-0.2.0/.cargo-checksum.json create mode 100644 commoncrypto-0.2.0/Cargo.toml create mode 100644 commoncrypto-0.2.0/src/hash.rs create mode 100644 commoncrypto-0.2.0/src/lib.rs create mode 100644 commoncrypto-0.2.0/src/pbkdf2.rs create mode 100644 commoncrypto-0.2.0/tests/hash.rs create mode 100644 commoncrypto-0.2.0/tests/pbkdf2.rs create mode 100644 commoncrypto-sys-0.2.0/.cargo-checksum.json create mode 100644 commoncrypto-sys-0.2.0/Cargo.toml create mode 100644 commoncrypto-sys-0.2.0/src/lib.rs create mode 100644 commoncrypto-sys-0.2.0/tests/hash.rs create mode 100644 commoncrypto-sys-0.2.0/tests/pbkdf2.rs create mode 100644 core-foundation-0.4.6/.cargo-checksum.json create mode 100644 core-foundation-0.4.6/Cargo.toml create mode 100644 core-foundation-0.4.6/src/array.rs create mode 100644 core-foundation-0.4.6/src/base.rs create mode 100644 core-foundation-0.4.6/src/boolean.rs create mode 100644 core-foundation-0.4.6/src/bundle.rs create mode 100644 core-foundation-0.4.6/src/data.rs create mode 100644 core-foundation-0.4.6/src/date.rs create mode 100644 core-foundation-0.4.6/src/dictionary.rs create mode 100644 core-foundation-0.4.6/src/error.rs create mode 100644 core-foundation-0.4.6/src/lib.rs create mode 100644 core-foundation-0.4.6/src/number.rs create mode 100644 core-foundation-0.4.6/src/propertylist.rs create mode 100644 core-foundation-0.4.6/src/runloop.rs create mode 100644 core-foundation-0.4.6/src/set.rs create mode 100644 core-foundation-0.4.6/src/string.rs create mode 100644 core-foundation-0.4.6/src/timezone.rs create mode 100644 core-foundation-0.4.6/src/url.rs create mode 100644 core-foundation-0.4.6/src/uuid.rs create mode 100644 core-foundation-sys-0.4.6/.cargo-checksum.json create mode 100644 core-foundation-sys-0.4.6/Cargo.toml create mode 100644 core-foundation-sys-0.4.6/build.rs create mode 100644 core-foundation-sys-0.4.6/src/array.rs create mode 100644 core-foundation-sys-0.4.6/src/base.rs create mode 100644 core-foundation-sys-0.4.6/src/bundle.rs create mode 100644 core-foundation-sys-0.4.6/src/data.rs create mode 100644 core-foundation-sys-0.4.6/src/date.rs create mode 100644 core-foundation-sys-0.4.6/src/dictionary.rs create mode 100644 core-foundation-sys-0.4.6/src/error.rs create mode 100644 core-foundation-sys-0.4.6/src/lib.rs create mode 100644 core-foundation-sys-0.4.6/src/messageport.rs create mode 100644 core-foundation-sys-0.4.6/src/number.rs create mode 100644 core-foundation-sys-0.4.6/src/propertylist.rs create mode 100644 core-foundation-sys-0.4.6/src/runloop.rs create mode 100644 core-foundation-sys-0.4.6/src/set.rs create mode 100644 core-foundation-sys-0.4.6/src/string.rs create mode 100644 core-foundation-sys-0.4.6/src/timezone.rs create mode 100644 core-foundation-sys-0.4.6/src/url.rs create mode 100644 core-foundation-sys-0.4.6/src/uuid.rs create mode 100644 crossbeam-0.2.12/.cargo-checksum.json create mode 100644 crossbeam-0.2.12/.travis.yml create mode 100644 crossbeam-0.2.12/CHANGELOG.md create mode 100644 crossbeam-0.2.12/Cargo.toml create mode 100644 crossbeam-0.2.12/LICENSE-APACHE create mode 100644 crossbeam-0.2.12/LICENSE-MIT create mode 100644 crossbeam-0.2.12/README.md create mode 100644 crossbeam-0.2.12/scala-bench/bench.scala create mode 100755 crossbeam-0.2.12/src/bin/bench.rs create mode 100644 crossbeam-0.2.12/src/bin/extra_impls/mod.rs create mode 100644 crossbeam-0.2.12/src/bin/extra_impls/mpsc_queue.rs create mode 100644 crossbeam-0.2.12/src/bin/stress-msq.rs create mode 100644 crossbeam-0.2.12/src/lib.rs create mode 100644 crossbeam-0.2.12/src/mem/cache_padded.rs create mode 100644 crossbeam-0.2.12/src/mem/epoch/atomic.rs create mode 100644 crossbeam-0.2.12/src/mem/epoch/garbage.rs create mode 100644 crossbeam-0.2.12/src/mem/epoch/global.rs create mode 100644 crossbeam-0.2.12/src/mem/epoch/guard.rs create mode 100644 crossbeam-0.2.12/src/mem/epoch/local.rs create mode 100644 crossbeam-0.2.12/src/mem/epoch/mod.rs create mode 100644 crossbeam-0.2.12/src/mem/epoch/participant.rs create mode 100644 crossbeam-0.2.12/src/mem/epoch/participants.rs create mode 100644 crossbeam-0.2.12/src/mem/mod.rs create mode 100644 crossbeam-0.2.12/src/scoped.rs create mode 100644 crossbeam-0.2.12/src/sync/arc_cell.rs create mode 100644 crossbeam-0.2.12/src/sync/atomic_option.rs create mode 100644 crossbeam-0.2.12/src/sync/chase_lev.rs create mode 100644 crossbeam-0.2.12/src/sync/mod.rs create mode 100644 crossbeam-0.2.12/src/sync/ms_queue.rs create mode 100644 crossbeam-0.2.12/src/sync/seg_queue.rs create mode 100644 crossbeam-0.2.12/src/sync/treiber_stack.rs create mode 100644 crossbeam-0.3.2/.cargo-checksum.json create mode 100644 crossbeam-0.3.2/.travis.yml create mode 100644 crossbeam-0.3.2/CHANGELOG.md create mode 100644 crossbeam-0.3.2/Cargo.toml create mode 100644 crossbeam-0.3.2/LICENSE-APACHE create mode 100644 crossbeam-0.3.2/LICENSE-MIT create mode 100644 crossbeam-0.3.2/README.md create mode 100644 crossbeam-0.3.2/src/bin/bench.rs create mode 100644 crossbeam-0.3.2/src/bin/extra_impls/mod.rs create mode 100644 crossbeam-0.3.2/src/bin/extra_impls/mpsc_queue.rs create mode 100644 crossbeam-0.3.2/src/bin/stress-msq.rs create mode 100644 crossbeam-0.3.2/src/cache_padded.rs create mode 100644 crossbeam-0.3.2/src/epoch/atomic.rs create mode 100644 crossbeam-0.3.2/src/epoch/garbage.rs create mode 100644 crossbeam-0.3.2/src/epoch/global.rs create mode 100644 crossbeam-0.3.2/src/epoch/guard.rs create mode 100644 crossbeam-0.3.2/src/epoch/local.rs create mode 100644 crossbeam-0.3.2/src/epoch/mod.rs create mode 100644 crossbeam-0.3.2/src/epoch/participant.rs create mode 100644 crossbeam-0.3.2/src/epoch/participants.rs create mode 100644 crossbeam-0.3.2/src/lib.rs create mode 100644 crossbeam-0.3.2/src/scoped.rs create mode 100644 crossbeam-0.3.2/src/sync/arc_cell.rs create mode 100644 crossbeam-0.3.2/src/sync/atomic_option.rs create mode 100644 crossbeam-0.3.2/src/sync/chase_lev.rs create mode 100644 crossbeam-0.3.2/src/sync/mod.rs create mode 100644 crossbeam-0.3.2/src/sync/ms_queue.rs create mode 100644 crossbeam-0.3.2/src/sync/seg_queue.rs create mode 100644 crossbeam-0.3.2/src/sync/treiber_stack.rs create mode 100644 crypt32-sys-0.2.0/.cargo-checksum.json create mode 100644 crypt32-sys-0.2.0/Cargo.toml create mode 100644 crypt32-sys-0.2.0/README.md create mode 100644 crypt32-sys-0.2.0/build.rs create mode 100644 crypt32-sys-0.2.0/src/lib.rs create mode 100644 crypto-hash-0.3.0/.cargo-checksum.json create mode 100644 crypto-hash-0.3.0/CONTRIBUTING.md create mode 100644 crypto-hash-0.3.0/Cargo.toml create mode 100644 crypto-hash-0.3.0/LICENSE create mode 100644 crypto-hash-0.3.0/Makefile create mode 100644 crypto-hash-0.3.0/NEWS.md create mode 100644 crypto-hash-0.3.0/README.md create mode 100644 crypto-hash-0.3.0/src/imp/commoncrypto.rs create mode 100644 crypto-hash-0.3.0/src/imp/cryptoapi.rs create mode 100644 crypto-hash-0.3.0/src/imp/openssl.rs create mode 100644 crypto-hash-0.3.0/src/lib.rs create mode 100644 crypto-hash-0.3.0/src/test.rs create mode 100644 curl-0.4.11/.cargo-checksum.json create mode 100644 curl-0.4.11/.gitmodules create mode 100644 curl-0.4.11/.travis.yml create mode 100644 curl-0.4.11/Cargo.toml create mode 100644 curl-0.4.11/LICENSE create mode 100644 curl-0.4.11/README.md create mode 100644 curl-0.4.11/appveyor.yml create mode 100644 curl-0.4.11/ci/.cargo/config create mode 100644 curl-0.4.11/ci/Dockerfile-linux32 create mode 100644 curl-0.4.11/ci/Dockerfile-linux64 create mode 100644 curl-0.4.11/ci/Dockerfile-linux64-curl create mode 100644 curl-0.4.11/ci/Dockerfile-mingw create mode 100644 curl-0.4.11/ci/Dockerfile-musl create mode 100644 curl-0.4.11/ci/run.sh create mode 100644 curl-0.4.11/src/easy/form.rs create mode 100644 curl-0.4.11/src/easy/handle.rs create mode 100644 curl-0.4.11/src/easy/handler.rs create mode 100644 curl-0.4.11/src/easy/list.rs create mode 100644 curl-0.4.11/src/easy/mod.rs create mode 100644 curl-0.4.11/src/easy/windows.rs create mode 100644 curl-0.4.11/src/error.rs create mode 100644 curl-0.4.11/src/lib.rs create mode 100644 curl-0.4.11/src/multi.rs create mode 100644 curl-0.4.11/src/panic.rs create mode 100644 curl-0.4.11/src/version.rs create mode 100644 curl-0.4.11/tests/easy.rs create mode 100644 curl-0.4.11/tests/formdata create mode 100644 curl-0.4.11/tests/multi.rs create mode 100644 curl-0.4.11/tests/post.rs create mode 100644 curl-0.4.11/tests/server/mod.rs create mode 100644 curl-sys-0.4.1/.cargo-checksum.json create mode 100644 curl-sys-0.4.1/Cargo.toml create mode 100644 curl-sys-0.4.1/LICENSE create mode 100644 curl-sys-0.4.1/build.rs create mode 100644 curl-sys-0.4.1/lib.rs create mode 100644 docopt-0.8.3/.cargo-checksum.json create mode 100644 docopt-0.8.3/.travis.yml create mode 100644 docopt-0.8.3/COPYING create mode 100644 docopt-0.8.3/Cargo.toml create mode 100644 docopt-0.8.3/LICENSE-MIT create mode 100644 docopt-0.8.3/Makefile create mode 100644 docopt-0.8.3/README.md create mode 100644 docopt-0.8.3/UNLICENSE create mode 100644 docopt-0.8.3/completions/docopt-wordlist.bash create mode 100644 docopt-0.8.3/ctags.rust create mode 100644 docopt-0.8.3/examples/cargo.rs create mode 100644 docopt-0.8.3/examples/cp.rs create mode 100644 docopt-0.8.3/examples/decode.rs create mode 100644 docopt-0.8.3/examples/hashmap.rs create mode 100644 docopt-0.8.3/examples/optional_command.rs create mode 100644 docopt-0.8.3/examples/verbose_multiple.rs create mode 100755 docopt-0.8.3/scripts/mk-testcases create mode 100644 docopt-0.8.3/session.vim create mode 100644 docopt-0.8.3/src/dopt.rs create mode 100644 docopt-0.8.3/src/lib.rs create mode 100644 docopt-0.8.3/src/parse.rs create mode 100644 docopt-0.8.3/src/synonym.rs create mode 100644 docopt-0.8.3/src/test/mod.rs create mode 100644 docopt-0.8.3/src/test/suggestions.rs create mode 100644 docopt-0.8.3/src/test/testcases.docopt create mode 100644 docopt-0.8.3/src/test/testcases.rs create mode 100644 docopt-0.8.3/src/wordlist.rs create mode 100644 dtoa-0.4.2/.cargo-checksum.json create mode 100644 dtoa-0.4.2/.travis.yml create mode 100644 dtoa-0.4.2/Cargo.toml create mode 100644 dtoa-0.4.2/LICENSE-APACHE create mode 100644 dtoa-0.4.2/LICENSE-MIT create mode 100644 dtoa-0.4.2/README.md create mode 100644 dtoa-0.4.2/benches/bench.rs create mode 100644 dtoa-0.4.2/src/diyfp.rs create mode 100644 dtoa-0.4.2/src/dtoa.rs create mode 100644 dtoa-0.4.2/src/lib.rs create mode 100644 dtoa-0.4.2/tests/test.rs create mode 100644 env_logger-0.4.3/.cargo-checksum.json create mode 100644 env_logger-0.4.3/Cargo.toml create mode 100644 env_logger-0.4.3/LICENSE-APACHE create mode 100644 env_logger-0.4.3/LICENSE-MIT create mode 100644 env_logger-0.4.3/src/lib.rs create mode 100644 env_logger-0.4.3/src/regex.rs create mode 100644 env_logger-0.4.3/src/string.rs create mode 100644 env_logger-0.4.3/tests/regexp_filter.rs create mode 100644 error-chain-0.11.0/.cargo-checksum.json create mode 100644 error-chain-0.11.0/.travis.yml create mode 100644 error-chain-0.11.0/CHANGELOG.md create mode 100644 error-chain-0.11.0/Cargo.toml create mode 100644 error-chain-0.11.0/LICENSE-APACHE create mode 100644 error-chain-0.11.0/LICENSE-MIT create mode 100644 error-chain-0.11.0/README.md create mode 100644 error-chain-0.11.0/examples/all.rs create mode 100644 error-chain-0.11.0/examples/chain_err.rs create mode 100644 error-chain-0.11.0/examples/doc.rs create mode 100644 error-chain-0.11.0/examples/quickstart.rs create mode 100644 error-chain-0.11.0/examples/size.rs create mode 100644 error-chain-0.11.0/src/bin/has_backtrace.rs create mode 100644 error-chain-0.11.0/src/error_chain.rs create mode 100644 error-chain-0.11.0/src/example_generated.rs create mode 100644 error-chain-0.11.0/src/impl_error_chain_kind.rs create mode 100644 error-chain-0.11.0/src/lib.rs create mode 100644 error-chain-0.11.0/src/quick_main.rs create mode 100644 error-chain-0.11.0/tests/quick_main.rs create mode 100644 error-chain-0.11.0/tests/tests.rs create mode 100644 filetime-0.1.14/.cargo-checksum.json create mode 100644 filetime-0.1.14/.travis.yml create mode 100644 filetime-0.1.14/Cargo.toml create mode 100644 filetime-0.1.14/LICENSE-APACHE create mode 100644 filetime-0.1.14/LICENSE-MIT create mode 100644 filetime-0.1.14/README.md create mode 100644 filetime-0.1.14/appveyor.yml create mode 100644 filetime-0.1.14/src/lib.rs create mode 100644 filetime-0.1.14/src/redox.rs create mode 100644 filetime-0.1.14/src/unix/linux.rs create mode 100644 filetime-0.1.14/src/unix/mod.rs create mode 100644 filetime-0.1.14/src/unix/utimensat.rs create mode 100644 filetime-0.1.14/src/unix/utimes.rs create mode 100644 filetime-0.1.14/src/windows.rs create mode 100644 flate2-0.2.20/.cargo-checksum.json create mode 100644 flate2-0.2.20/.travis.yml create mode 100644 flate2-0.2.20/Cargo.toml create mode 100644 flate2-0.2.20/LICENSE-APACHE create mode 100644 flate2-0.2.20/LICENSE-MIT create mode 100644 flate2-0.2.20/README.md create mode 100644 flate2-0.2.20/appveyor.yml create mode 100644 flate2-0.2.20/examples/deflatedecoder-bufread.rs create mode 100644 flate2-0.2.20/examples/deflatedecoder-read.rs create mode 100644 flate2-0.2.20/examples/deflatedecoder-write.rs create mode 100644 flate2-0.2.20/examples/deflateencoder-bufread.rs create mode 100644 flate2-0.2.20/examples/deflateencoder-read.rs create mode 100644 flate2-0.2.20/examples/deflateencoder-write.rs create mode 100644 flate2-0.2.20/examples/flatereadext.rs create mode 100644 flate2-0.2.20/examples/gzbuilder.rs create mode 100644 flate2-0.2.20/examples/gzdecoder-bufread.rs create mode 100644 flate2-0.2.20/examples/gzdecoder-read.rs create mode 100644 flate2-0.2.20/examples/gzencoder-bufread.rs create mode 100644 flate2-0.2.20/examples/gzencoder-read.rs create mode 100644 flate2-0.2.20/examples/gzencoder-write.rs create mode 100644 flate2-0.2.20/examples/gzmultidecoder-bufread.rs create mode 100644 flate2-0.2.20/examples/gzmultidecoder-read.rs create mode 100644 flate2-0.2.20/examples/hello_world.txt create mode 100644 flate2-0.2.20/examples/zlibdecoder-bufread.rs create mode 100644 flate2-0.2.20/examples/zlibdecoder-read.rs create mode 100644 flate2-0.2.20/examples/zlibdecoder-write.rs create mode 100644 flate2-0.2.20/examples/zlibencoder-bufread.rs create mode 100644 flate2-0.2.20/examples/zlibencoder-read.rs create mode 100644 flate2-0.2.20/examples/zlibencoder-write.rs create mode 100644 flate2-0.2.20/src/bufreader.rs create mode 100644 flate2-0.2.20/src/crc.rs create mode 100644 flate2-0.2.20/src/deflate/bufread.rs create mode 100644 flate2-0.2.20/src/deflate/mod.rs create mode 100644 flate2-0.2.20/src/deflate/read.rs create mode 100644 flate2-0.2.20/src/deflate/write.rs create mode 100644 flate2-0.2.20/src/ffi.rs create mode 100644 flate2-0.2.20/src/gz/bufread.rs create mode 100644 flate2-0.2.20/src/gz/mod.rs create mode 100644 flate2-0.2.20/src/gz/read.rs create mode 100644 flate2-0.2.20/src/gz/write.rs create mode 100644 flate2-0.2.20/src/lib.rs create mode 100644 flate2-0.2.20/src/mem.rs create mode 100644 flate2-0.2.20/src/zio.rs create mode 100644 flate2-0.2.20/src/zlib/bufread.rs create mode 100644 flate2-0.2.20/src/zlib/mod.rs create mode 100644 flate2-0.2.20/src/zlib/read.rs create mode 100644 flate2-0.2.20/src/zlib/write.rs create mode 100644 flate2-0.2.20/tests/corrupt-file.gz create mode 100644 flate2-0.2.20/tests/early-flush.rs create mode 100644 flate2-0.2.20/tests/good-file.gz create mode 100644 flate2-0.2.20/tests/good-file.txt create mode 100644 flate2-0.2.20/tests/gunzip.rs create mode 100644 flate2-0.2.20/tests/multi.gz create mode 100644 flate2-0.2.20/tests/multi.txt create mode 100644 flate2-0.2.20/tests/tokio.rs create mode 100644 flate2-0.2.20/tests/zero-write.rs create mode 100644 fnv-1.0.6/.cargo-checksum.json create mode 100644 fnv-1.0.6/.travis.yml create mode 100644 fnv-1.0.6/Cargo.toml create mode 100644 fnv-1.0.6/LICENSE-APACHE create mode 100644 fnv-1.0.6/LICENSE-MIT create mode 100644 fnv-1.0.6/README.md create mode 100644 fnv-1.0.6/lib.rs create mode 100644 foreign-types-0.3.2/.cargo-checksum.json create mode 100644 foreign-types-0.3.2/Cargo.toml create mode 100644 foreign-types-0.3.2/LICENSE-APACHE create mode 100644 foreign-types-0.3.2/LICENSE-MIT create mode 100644 foreign-types-0.3.2/README.md create mode 100644 foreign-types-0.3.2/src/lib.rs create mode 100644 foreign-types-shared-0.1.1/.cargo-checksum.json create mode 100644 foreign-types-shared-0.1.1/Cargo.toml create mode 100644 foreign-types-shared-0.1.1/LICENSE-APACHE create mode 100644 foreign-types-shared-0.1.1/LICENSE-MIT create mode 100644 foreign-types-shared-0.1.1/src/lib.rs create mode 100644 fs2-0.4.3/.appveyor.yml create mode 100644 fs2-0.4.3/.cargo-checksum.json create mode 100644 fs2-0.4.3/.travis.yml create mode 100644 fs2-0.4.3/Cargo.toml create mode 100644 fs2-0.4.3/LICENSE-APACHE create mode 100644 fs2-0.4.3/LICENSE-MIT create mode 100644 fs2-0.4.3/README.md create mode 100644 fs2-0.4.3/src/lib.rs create mode 100644 fs2-0.4.3/src/unix.rs create mode 100644 fs2-0.4.3/src/windows.rs create mode 100644 fuchsia-zircon-0.3.3/.cargo-checksum.json create mode 100644 fuchsia-zircon-0.3.3/BUILD.gn create mode 100644 fuchsia-zircon-0.3.3/Cargo.toml create mode 100644 fuchsia-zircon-0.3.3/LICENSE create mode 100644 fuchsia-zircon-0.3.3/README.md create mode 100644 fuchsia-zircon-0.3.3/examples/BUILD.gn create mode 100644 fuchsia-zircon-0.3.3/src/channel.rs create mode 100644 fuchsia-zircon-0.3.3/src/cprng.rs create mode 100644 fuchsia-zircon-0.3.3/src/event.rs create mode 100644 fuchsia-zircon-0.3.3/src/eventpair.rs create mode 100644 fuchsia-zircon-0.3.3/src/fifo.rs create mode 100644 fuchsia-zircon-0.3.3/src/handle.rs create mode 100644 fuchsia-zircon-0.3.3/src/job.rs create mode 100644 fuchsia-zircon-0.3.3/src/lib.rs create mode 100644 fuchsia-zircon-0.3.3/src/port.rs create mode 100644 fuchsia-zircon-0.3.3/src/process.rs create mode 100644 fuchsia-zircon-0.3.3/src/rights.rs create mode 100644 fuchsia-zircon-0.3.3/src/signals.rs create mode 100644 fuchsia-zircon-0.3.3/src/socket.rs create mode 100644 fuchsia-zircon-0.3.3/src/status.rs create mode 100644 fuchsia-zircon-0.3.3/src/thread.rs create mode 100644 fuchsia-zircon-0.3.3/src/time.rs create mode 100644 fuchsia-zircon-0.3.3/src/vmar.rs create mode 100644 fuchsia-zircon-0.3.3/src/vmo.rs create mode 100755 fuchsia-zircon-0.3.3/tools/gen_status.py create mode 100644 fuchsia-zircon-sys-0.3.3/.cargo-checksum.json create mode 100644 fuchsia-zircon-sys-0.3.3/BUILD.gn create mode 100644 fuchsia-zircon-sys-0.3.3/Cargo.toml create mode 100644 fuchsia-zircon-sys-0.3.3/examples/hello.rs create mode 100644 fuchsia-zircon-sys-0.3.3/src/definitions.rs create mode 100644 fuchsia-zircon-sys-0.3.3/src/lib.rs create mode 100644 git2-0.6.11/.cargo-checksum.json create mode 100644 git2-0.6.11/.gitmodules create mode 100644 git2-0.6.11/.travis.yml create mode 100644 git2-0.6.11/Cargo.toml create mode 100644 git2-0.6.11/LICENSE-APACHE create mode 100644 git2-0.6.11/LICENSE-MIT create mode 100644 git2-0.6.11/README.md create mode 100644 git2-0.6.11/appveyor.yml create mode 100644 git2-0.6.11/examples/add.rs create mode 100644 git2-0.6.11/examples/blame.rs create mode 100644 git2-0.6.11/examples/cat-file.rs create mode 100644 git2-0.6.11/examples/clone.rs create mode 100644 git2-0.6.11/examples/diff.rs create mode 100644 git2-0.6.11/examples/fetch.rs create mode 100644 git2-0.6.11/examples/init.rs create mode 100644 git2-0.6.11/examples/log.rs create mode 100644 git2-0.6.11/examples/ls-remote.rs create mode 100644 git2-0.6.11/examples/rev-list.rs create mode 100644 git2-0.6.11/examples/rev-parse.rs create mode 100644 git2-0.6.11/examples/status.rs create mode 100644 git2-0.6.11/examples/tag.rs create mode 100644 git2-0.6.11/src/blame.rs create mode 100644 git2-0.6.11/src/blob.rs create mode 100644 git2-0.6.11/src/branch.rs create mode 100644 git2-0.6.11/src/buf.rs create mode 100644 git2-0.6.11/src/build.rs create mode 100644 git2-0.6.11/src/call.rs create mode 100644 git2-0.6.11/src/cert.rs create mode 100644 git2-0.6.11/src/commit.rs create mode 100644 git2-0.6.11/src/config.rs create mode 100644 git2-0.6.11/src/cred.rs create mode 100644 git2-0.6.11/src/describe.rs create mode 100644 git2-0.6.11/src/diff.rs create mode 100644 git2-0.6.11/src/error.rs create mode 100644 git2-0.6.11/src/index.rs create mode 100644 git2-0.6.11/src/lib.rs create mode 100644 git2-0.6.11/src/merge.rs create mode 100644 git2-0.6.11/src/message.rs create mode 100644 git2-0.6.11/src/note.rs create mode 100644 git2-0.6.11/src/object.rs create mode 100644 git2-0.6.11/src/odb.rs create mode 100644 git2-0.6.11/src/oid.rs create mode 100644 git2-0.6.11/src/oid_array.rs create mode 100644 git2-0.6.11/src/packbuilder.rs create mode 100644 git2-0.6.11/src/panic.rs create mode 100644 git2-0.6.11/src/patch.rs create mode 100644 git2-0.6.11/src/pathspec.rs create mode 100644 git2-0.6.11/src/proxy_options.rs create mode 100644 git2-0.6.11/src/reference.rs create mode 100644 git2-0.6.11/src/reflog.rs create mode 100644 git2-0.6.11/src/refspec.rs create mode 100644 git2-0.6.11/src/remote.rs create mode 100644 git2-0.6.11/src/remote_callbacks.rs create mode 100644 git2-0.6.11/src/repo.rs create mode 100644 git2-0.6.11/src/revspec.rs create mode 100644 git2-0.6.11/src/revwalk.rs create mode 100644 git2-0.6.11/src/signature.rs create mode 100644 git2-0.6.11/src/stash.rs create mode 100644 git2-0.6.11/src/status.rs create mode 100644 git2-0.6.11/src/string_array.rs create mode 100644 git2-0.6.11/src/submodule.rs create mode 100644 git2-0.6.11/src/tag.rs create mode 100644 git2-0.6.11/src/test.rs create mode 100644 git2-0.6.11/src/time.rs create mode 100644 git2-0.6.11/src/transport.rs create mode 100644 git2-0.6.11/src/tree.rs create mode 100644 git2-0.6.11/src/treebuilder.rs create mode 100644 git2-0.6.11/src/util.rs create mode 100644 git2-curl-0.7.0/.cargo-checksum.json create mode 100644 git2-curl-0.7.0/Cargo.toml create mode 100644 git2-curl-0.7.0/src/lib.rs create mode 100644 git2-curl-0.7.0/tests/all.rs create mode 100644 glob-0.2.11/.cargo-checksum.json create mode 100644 glob-0.2.11/.travis.yml create mode 100644 glob-0.2.11/Cargo.toml create mode 100644 glob-0.2.11/LICENSE-APACHE create mode 100644 glob-0.2.11/LICENSE-MIT create mode 100644 glob-0.2.11/README.md create mode 100644 glob-0.2.11/src/lib.rs create mode 100644 glob-0.2.11/tests/glob-std.rs create mode 100644 globset-0.2.1/.cargo-checksum.json create mode 100644 globset-0.2.1/COPYING create mode 100644 globset-0.2.1/Cargo.toml create mode 100644 globset-0.2.1/LICENSE-MIT create mode 100644 globset-0.2.1/README.md create mode 100644 globset-0.2.1/UNLICENSE create mode 100644 globset-0.2.1/benches/bench.rs create mode 100644 globset-0.2.1/src/glob.rs create mode 100644 globset-0.2.1/src/lib.rs create mode 100644 globset-0.2.1/src/pathutil.rs create mode 100644 hamcrest-0.1.1/.cargo-checksum.json create mode 100644 hamcrest-0.1.1/.travis.yml create mode 100644 hamcrest-0.1.1/CHANGELOG.md create mode 100644 hamcrest-0.1.1/Cargo.toml create mode 100644 hamcrest-0.1.1/LICENSE-APACHE create mode 100644 hamcrest-0.1.1/LICENSE-MIT create mode 100644 hamcrest-0.1.1/README.md create mode 100644 hamcrest-0.1.1/src/core.rs create mode 100644 hamcrest-0.1.1/src/lib.rs create mode 100644 hamcrest-0.1.1/src/matchers/close_to.rs create mode 100644 hamcrest-0.1.1/src/matchers/equal_to.rs create mode 100644 hamcrest-0.1.1/src/matchers/existing_path.rs create mode 100644 hamcrest-0.1.1/src/matchers/is.rs create mode 100644 hamcrest-0.1.1/src/matchers/mod.rs create mode 100644 hamcrest-0.1.1/src/matchers/none.rs create mode 100644 hamcrest-0.1.1/src/matchers/regex.rs create mode 100644 hamcrest-0.1.1/src/matchers/vecs.rs create mode 100644 hamcrest-0.1.1/tests/prelude.rs create mode 100644 hex-0.2.0/.cargo-checksum.json create mode 100644 hex-0.2.0/.travis.yml create mode 100644 hex-0.2.0/Cargo.toml create mode 100644 hex-0.2.0/LICENSE-APACHE create mode 100644 hex-0.2.0/LICENSE-MIT create mode 100644 hex-0.2.0/README.md create mode 100644 hex-0.2.0/rust-hex.sublime-project create mode 100644 hex-0.2.0/src/lib.rs create mode 100644 hex-0.2.0/toto.rs create mode 100644 home-0.3.0/.cargo-checksum.json create mode 100644 home-0.3.0/Cargo.toml create mode 100644 home-0.3.0/README.md create mode 100644 home-0.3.0/src/lib.rs create mode 100644 idna-0.1.4/.cargo-checksum.json create mode 100644 idna-0.1.4/Cargo.toml create mode 100644 idna-0.1.4/LICENSE-APACHE create mode 100644 idna-0.1.4/LICENSE-MIT create mode 100644 idna-0.1.4/src/IdnaMappingTable.txt create mode 100644 idna-0.1.4/src/lib.rs create mode 100644 idna-0.1.4/src/make_uts46_mapping_table.py create mode 100644 idna-0.1.4/src/punycode.rs create mode 100644 idna-0.1.4/src/uts46.rs create mode 100644 idna-0.1.4/src/uts46_mapping_table.rs create mode 100644 idna-0.1.4/tests/IdnaTest.txt create mode 100644 idna-0.1.4/tests/punycode.rs create mode 100644 idna-0.1.4/tests/punycode_tests.json create mode 100644 idna-0.1.4/tests/tests.rs create mode 100644 idna-0.1.4/tests/unit.rs create mode 100644 idna-0.1.4/tests/uts46.rs create mode 100644 ignore-0.2.2/.cargo-checksum.json create mode 100644 ignore-0.2.2/COPYING create mode 100644 ignore-0.2.2/Cargo.toml create mode 100644 ignore-0.2.2/LICENSE-MIT create mode 100644 ignore-0.2.2/README.md create mode 100644 ignore-0.2.2/UNLICENSE create mode 100644 ignore-0.2.2/examples/walk.rs create mode 100644 ignore-0.2.2/src/dir.rs create mode 100644 ignore-0.2.2/src/gitignore.rs create mode 100644 ignore-0.2.2/src/lib.rs create mode 100644 ignore-0.2.2/src/overrides.rs create mode 100644 ignore-0.2.2/src/pathutil.rs create mode 100644 ignore-0.2.2/src/types.rs create mode 100644 ignore-0.2.2/src/walk.rs create mode 100644 ignore-0.2.2/tests/gitignore_matched_path_or_any_parents_tests.gitignore create mode 100644 ignore-0.2.2/tests/gitignore_matched_path_or_any_parents_tests.rs create mode 100644 itoa-0.3.4/.cargo-checksum.json create mode 100644 itoa-0.3.4/.travis.yml create mode 100644 itoa-0.3.4/Cargo.toml create mode 100644 itoa-0.3.4/LICENSE-APACHE create mode 100644 itoa-0.3.4/LICENSE-MIT create mode 100644 itoa-0.3.4/README.md create mode 100644 itoa-0.3.4/benches/bench.rs create mode 100644 itoa-0.3.4/src/lib.rs create mode 100644 itoa-0.3.4/src/udiv128.rs create mode 100644 itoa-0.3.4/tests/test.rs create mode 100644 jobserver-0.1.9/.appveyor.yml create mode 100644 jobserver-0.1.9/.cargo-checksum.json create mode 100644 jobserver-0.1.9/.travis.yml create mode 100644 jobserver-0.1.9/Cargo.toml create mode 100644 jobserver-0.1.9/LICENSE-APACHE create mode 100644 jobserver-0.1.9/LICENSE-MIT create mode 100644 jobserver-0.1.9/README.md create mode 100644 jobserver-0.1.9/src/lib.rs create mode 100644 jobserver-0.1.9/tests/client-of-myself.rs create mode 100644 jobserver-0.1.9/tests/client.rs create mode 100644 jobserver-0.1.9/tests/helper.rs create mode 100644 jobserver-0.1.9/tests/make-as-a-client.rs create mode 100644 jobserver-0.1.9/tests/server.rs create mode 100644 kernel32-sys-0.2.2/.cargo-checksum.json create mode 100644 kernel32-sys-0.2.2/Cargo.toml create mode 100644 kernel32-sys-0.2.2/README.md create mode 100644 kernel32-sys-0.2.2/build.rs create mode 100644 kernel32-sys-0.2.2/src/lib.rs create mode 100644 lazy_static-0.2.11/.cargo-checksum.json create mode 100644 lazy_static-0.2.11/.travis.yml create mode 100644 lazy_static-0.2.11/Cargo.toml create mode 100644 lazy_static-0.2.11/LICENSE-APACHE create mode 100644 lazy_static-0.2.11/LICENSE-MIT create mode 100644 lazy_static-0.2.11/README.md create mode 100644 lazy_static-0.2.11/appveyor.yml create mode 100644 lazy_static-0.2.11/src/core_lazy.rs create mode 100644 lazy_static-0.2.11/src/lazy.rs create mode 100644 lazy_static-0.2.11/src/lib.rs create mode 100644 lazy_static-0.2.11/src/nightly_lazy.rs create mode 100644 lazy_static-0.2.11/tests/compile-fail/README.md create mode 100644 lazy_static-0.2.11/tests/compile-fail/incorrect_visibility_restriction.rs create mode 100644 lazy_static-0.2.11/tests/compile-fail/static_is_private.rs create mode 100644 lazy_static-0.2.11/tests/compile-fail/static_is_sized.rs create mode 100644 lazy_static-0.2.11/tests/compile-fail/static_never_used.rs create mode 100644 lazy_static-0.2.11/tests/compile_tests.rs create mode 100644 lazy_static-0.2.11/tests/no_std.rs create mode 100644 lazy_static-0.2.11/tests/test.rs create mode 100644 lazy_static-1.0.0/.cargo-checksum.json create mode 100644 lazy_static-1.0.0/.travis.yml create mode 100644 lazy_static-1.0.0/Cargo.toml create mode 100644 lazy_static-1.0.0/LICENSE-APACHE create mode 100644 lazy_static-1.0.0/LICENSE-MIT create mode 100644 lazy_static-1.0.0/README.md create mode 100644 lazy_static-1.0.0/appveyor.yml create mode 100644 lazy_static-1.0.0/src/core_lazy.rs create mode 100644 lazy_static-1.0.0/src/lazy.rs create mode 100644 lazy_static-1.0.0/src/lib.rs create mode 100644 lazy_static-1.0.0/src/nightly_lazy.rs create mode 100644 lazy_static-1.0.0/tests/compile-fail/README.md create mode 100644 lazy_static-1.0.0/tests/compile-fail/incorrect_visibility_restriction.rs create mode 100644 lazy_static-1.0.0/tests/compile-fail/static_is_private.rs create mode 100644 lazy_static-1.0.0/tests/compile-fail/static_is_sized.rs create mode 100644 lazy_static-1.0.0/tests/compile-fail/static_never_used.rs create mode 100644 lazy_static-1.0.0/tests/compile_tests.rs create mode 100644 lazy_static-1.0.0/tests/no_std.rs create mode 100644 lazy_static-1.0.0/tests/test.rs create mode 100644 libc-0.2.35/.cargo-checksum.json create mode 100644 libc-0.2.35/.travis.yml create mode 100644 libc-0.2.35/Cargo.toml create mode 100644 libc-0.2.35/LICENSE-APACHE create mode 100644 libc-0.2.35/LICENSE-MIT create mode 100644 libc-0.2.35/README.md create mode 100644 libc-0.2.35/appveyor.yml create mode 100644 libc-0.2.35/ci/README.md create mode 100644 libc-0.2.35/ci/android-install-ndk.sh create mode 100644 libc-0.2.35/ci/android-install-sdk.sh create mode 100644 libc-0.2.35/ci/android-sysimage.sh create mode 100644 libc-0.2.35/ci/docker/aarch64-linux-android/Dockerfile create mode 100644 libc-0.2.35/ci/docker/aarch64-unknown-linux-gnu/Dockerfile create mode 100644 libc-0.2.35/ci/docker/aarch64-unknown-linux-musl/Dockerfile create mode 100644 libc-0.2.35/ci/docker/arm-linux-androideabi/Dockerfile create mode 100644 libc-0.2.35/ci/docker/arm-unknown-linux-gnueabihf/Dockerfile create mode 100644 libc-0.2.35/ci/docker/arm-unknown-linux-musleabihf/Dockerfile create mode 100644 libc-0.2.35/ci/docker/asmjs-unknown-emscripten/Dockerfile create mode 100644 libc-0.2.35/ci/docker/i686-linux-android/Dockerfile create mode 100644 libc-0.2.35/ci/docker/i686-unknown-linux-gnu/Dockerfile create mode 100644 libc-0.2.35/ci/docker/i686-unknown-linux-musl/Dockerfile create mode 100644 libc-0.2.35/ci/docker/mips-unknown-linux-gnu/Dockerfile create mode 100644 libc-0.2.35/ci/docker/mips-unknown-linux-musl/Dockerfile create mode 100644 libc-0.2.35/ci/docker/mips64-unknown-linux-gnuabi64/Dockerfile create mode 100644 libc-0.2.35/ci/docker/mips64el-unknown-linux-gnuabi64/Dockerfile create mode 100644 libc-0.2.35/ci/docker/mipsel-unknown-linux-musl/Dockerfile create mode 100644 libc-0.2.35/ci/docker/powerpc-unknown-linux-gnu/Dockerfile create mode 100644 libc-0.2.35/ci/docker/powerpc64-unknown-linux-gnu/Dockerfile create mode 100644 libc-0.2.35/ci/docker/powerpc64le-unknown-linux-gnu/Dockerfile create mode 100644 libc-0.2.35/ci/docker/s390x-unknown-linux-gnu/Dockerfile create mode 100644 libc-0.2.35/ci/docker/sparc64-unknown-linux-gnu/Dockerfile create mode 100644 libc-0.2.35/ci/docker/wasm32-unknown-emscripten/Dockerfile create mode 100755 libc-0.2.35/ci/docker/wasm32-unknown-emscripten/node-wrapper.sh create mode 100644 libc-0.2.35/ci/docker/x86_64-linux-android/Dockerfile create mode 100644 libc-0.2.35/ci/docker/x86_64-rumprun-netbsd/Dockerfile create mode 100644 libc-0.2.35/ci/docker/x86_64-rumprun-netbsd/runtest.rs create mode 100644 libc-0.2.35/ci/docker/x86_64-unknown-freebsd/Dockerfile create mode 100644 libc-0.2.35/ci/docker/x86_64-unknown-linux-gnu/Dockerfile create mode 100644 libc-0.2.35/ci/docker/x86_64-unknown-linux-gnux32/Dockerfile create mode 100644 libc-0.2.35/ci/docker/x86_64-unknown-linux-musl/Dockerfile create mode 100644 libc-0.2.35/ci/dox.sh create mode 100755 libc-0.2.35/ci/emscripten-entry.sh create mode 100644 libc-0.2.35/ci/emscripten.sh create mode 100644 libc-0.2.35/ci/ios/deploy_and_run_on_ios_simulator.rs create mode 100644 libc-0.2.35/ci/landing-page-footer.html create mode 100644 libc-0.2.35/ci/landing-page-head.html create mode 100644 libc-0.2.35/ci/linux-s390x.sh create mode 100644 libc-0.2.35/ci/linux-sparc64.sh create mode 100755 libc-0.2.35/ci/run-docker.sh create mode 100644 libc-0.2.35/ci/run-qemu.sh create mode 100755 libc-0.2.35/ci/run.sh create mode 100644 libc-0.2.35/ci/runtest-android.rs create mode 100644 libc-0.2.35/ci/style.rs create mode 100755 libc-0.2.35/ci/test-runner-linux create mode 100644 libc-0.2.35/src/cloudabi/aarch64.rs create mode 100644 libc-0.2.35/src/cloudabi/mod.rs create mode 100644 libc-0.2.35/src/cloudabi/x86.rs create mode 100644 libc-0.2.35/src/cloudabi/x86_64.rs create mode 100644 libc-0.2.35/src/dox.rs create mode 100644 libc-0.2.35/src/fuchsia/aarch64.rs create mode 100644 libc-0.2.35/src/fuchsia/mod.rs create mode 100644 libc-0.2.35/src/fuchsia/powerpc64.rs create mode 100644 libc-0.2.35/src/fuchsia/x86_64.rs create mode 100644 libc-0.2.35/src/lib.rs create mode 100644 libc-0.2.35/src/macros.rs create mode 100644 libc-0.2.35/src/redox/mod.rs create mode 100644 libc-0.2.35/src/redox/net.rs create mode 100644 libc-0.2.35/src/unix/bsd/apple/b32.rs create mode 100644 libc-0.2.35/src/unix/bsd/apple/b64.rs create mode 100644 libc-0.2.35/src/unix/bsd/apple/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/freebsdlike/dragonfly/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/freebsdlike/freebsd/aarch64.rs create mode 100644 libc-0.2.35/src/unix/bsd/freebsdlike/freebsd/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/freebsdlike/freebsd/x86.rs create mode 100644 libc-0.2.35/src/unix/bsd/freebsdlike/freebsd/x86_64.rs create mode 100644 libc-0.2.35/src/unix/bsd/freebsdlike/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/netbsd/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/netbsd/other/b32/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/netbsd/other/b64/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/netbsd/other/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/openbsdlike/bitrig/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/openbsdlike/bitrig/x86.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/openbsdlike/bitrig/x86_64.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/openbsdlike/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/openbsdlike/openbsd/aarch64.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/openbsdlike/openbsd/mod.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/openbsdlike/openbsd/x86.rs create mode 100644 libc-0.2.35/src/unix/bsd/netbsdlike/openbsdlike/openbsd/x86_64.rs create mode 100644 libc-0.2.35/src/unix/haiku/b32.rs create mode 100644 libc-0.2.35/src/unix/haiku/b64.rs create mode 100644 libc-0.2.35/src/unix/haiku/mod.rs create mode 100644 libc-0.2.35/src/unix/mod.rs create mode 100644 libc-0.2.35/src/unix/newlib/aarch64/mod.rs create mode 100644 libc-0.2.35/src/unix/newlib/arm/mod.rs create mode 100644 libc-0.2.35/src/unix/newlib/mod.rs create mode 100644 libc-0.2.35/src/unix/notbsd/android/b32/arm.rs create mode 100644 libc-0.2.35/src/unix/notbsd/android/b32/mod.rs create mode 100644 libc-0.2.35/src/unix/notbsd/android/b32/x86.rs create mode 100644 libc-0.2.35/src/unix/notbsd/android/b64/aarch64.rs create mode 100644 libc-0.2.35/src/unix/notbsd/android/b64/mod.rs create mode 100644 libc-0.2.35/src/unix/notbsd/android/b64/x86_64.rs create mode 100644 libc-0.2.35/src/unix/notbsd/android/mod.rs create mode 100644 libc-0.2.35/src/unix/notbsd/emscripten.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/mips/mips32.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/mips/mips64.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/mips/mod.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/mod.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/musl/b32/arm.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/musl/b32/mips.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/musl/b32/mod.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/musl/b32/x86.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/musl/b64/aarch64.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/musl/b64/mod.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/musl/b64/powerpc64.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/musl/b64/x86_64.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/musl/mod.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/other/b32/arm.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/other/b32/mod.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/other/b32/powerpc.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/other/b32/x86.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/other/b64/aarch64.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/other/b64/mod.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/other/b64/not_x32.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/other/b64/powerpc64.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/other/b64/sparc64.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/other/b64/x32.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/other/b64/x86_64.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/other/mod.rs create mode 100644 libc-0.2.35/src/unix/notbsd/linux/s390x.rs create mode 100644 libc-0.2.35/src/unix/notbsd/mod.rs create mode 100644 libc-0.2.35/src/unix/solaris/mod.rs create mode 100644 libc-0.2.35/src/unix/uclibc/mips/mips32.rs create mode 100644 libc-0.2.35/src/unix/uclibc/mips/mips64.rs create mode 100644 libc-0.2.35/src/unix/uclibc/mips/mod.rs create mode 100644 libc-0.2.35/src/unix/uclibc/mod.rs create mode 100644 libc-0.2.35/src/unix/uclibc/x86_64/l4re.rs create mode 100644 libc-0.2.35/src/unix/uclibc/x86_64/mod.rs create mode 100644 libc-0.2.35/src/windows.rs create mode 100644 libgit2-sys-0.6.19/.cargo-checksum.json create mode 100644 libgit2-sys-0.6.19/Cargo.toml create mode 100644 libgit2-sys-0.6.19/LICENSE-APACHE create mode 100644 libgit2-sys-0.6.19/LICENSE-MIT create mode 100644 libgit2-sys-0.6.19/build.rs create mode 100644 libgit2-sys-0.6.19/lib.rs create mode 100644 libssh2-sys-0.2.6/.cargo-checksum.json create mode 100644 libssh2-sys-0.2.6/Cargo.toml create mode 100644 libssh2-sys-0.2.6/build.rs create mode 100644 libssh2-sys-0.2.6/lib.rs create mode 100644 libz-sys-1.0.18/.cargo-checksum.json create mode 100644 libz-sys-1.0.18/.travis.yml create mode 100644 libz-sys-1.0.18/Cargo.toml create mode 100644 libz-sys-1.0.18/LICENSE-APACHE create mode 100644 libz-sys-1.0.18/LICENSE-MIT create mode 100644 libz-sys-1.0.18/README.md create mode 100644 libz-sys-1.0.18/appveyor.yml create mode 100644 libz-sys-1.0.18/build.rs create mode 100644 libz-sys-1.0.18/src/lib.rs create mode 100644 log-0.3.9/.cargo-checksum.json create mode 100644 log-0.3.9/.travis.yml create mode 100644 log-0.3.9/Cargo.toml create mode 100644 log-0.3.9/LICENSE-APACHE create mode 100644 log-0.3.9/LICENSE-MIT create mode 100644 log-0.3.9/README.md create mode 100644 log-0.3.9/appveyor.yml create mode 100644 log-0.3.9/src/lib.rs create mode 100644 log-0.3.9/src/macros.rs create mode 100644 log-0.4.1/.cargo-checksum.json create mode 100644 log-0.4.1/.travis.yml create mode 100644 log-0.4.1/CHANGELOG.md create mode 100644 log-0.4.1/Cargo.toml create mode 100644 log-0.4.1/LICENSE-APACHE create mode 100644 log-0.4.1/LICENSE-MIT create mode 100644 log-0.4.1/README.md create mode 100644 log-0.4.1/appveyor.yml create mode 100644 log-0.4.1/src/lib.rs create mode 100644 log-0.4.1/src/macros.rs create mode 100644 log-0.4.1/src/serde.rs create mode 100644 log-0.4.1/tests/filters.rs create mode 100644 matches-0.1.6/.cargo-checksum.json create mode 100644 matches-0.1.6/Cargo.toml create mode 100644 matches-0.1.6/LICENSE create mode 100644 matches-0.1.6/lib.rs create mode 100644 memchr-0.1.11/.cargo-checksum.json create mode 100644 memchr-0.1.11/.travis.yml create mode 100644 memchr-0.1.11/COPYING create mode 100644 memchr-0.1.11/Cargo.toml create mode 100644 memchr-0.1.11/LICENSE-MIT create mode 100644 memchr-0.1.11/Makefile create mode 100644 memchr-0.1.11/README.md create mode 100644 memchr-0.1.11/UNLICENSE create mode 100644 memchr-0.1.11/appveyor.yml create mode 100644 memchr-0.1.11/benches/bench.rs create mode 100644 memchr-0.1.11/ctags.rust create mode 100644 memchr-0.1.11/session.vim create mode 100644 memchr-0.1.11/src/lib.rs create mode 100644 memchr-1.0.2/.cargo-checksum.json create mode 100644 memchr-1.0.2/.travis.yml create mode 100644 memchr-1.0.2/COPYING create mode 100644 memchr-1.0.2/Cargo.toml create mode 100644 memchr-1.0.2/LICENSE-MIT create mode 100644 memchr-1.0.2/Makefile create mode 100644 memchr-1.0.2/README.md create mode 100644 memchr-1.0.2/UNLICENSE create mode 100644 memchr-1.0.2/appveyor.yml create mode 100644 memchr-1.0.2/benches/bench.rs create mode 100644 memchr-1.0.2/ctags.rust create mode 100644 memchr-1.0.2/session.vim create mode 100644 memchr-1.0.2/src/lib.rs create mode 100644 memchr-2.0.1/.cargo-checksum.json create mode 100644 memchr-2.0.1/.travis.yml create mode 100644 memchr-2.0.1/COPYING create mode 100644 memchr-2.0.1/Cargo.toml create mode 100644 memchr-2.0.1/LICENSE-MIT create mode 100644 memchr-2.0.1/Makefile create mode 100644 memchr-2.0.1/README.md create mode 100644 memchr-2.0.1/UNLICENSE create mode 100644 memchr-2.0.1/appveyor.yml create mode 100644 memchr-2.0.1/benches/bench.rs create mode 100644 memchr-2.0.1/ctags.rust create mode 100644 memchr-2.0.1/session.vim create mode 100644 memchr-2.0.1/src/lib.rs create mode 100644 miniz-sys-0.1.10/.cargo-checksum.json create mode 100644 miniz-sys-0.1.10/Cargo.toml create mode 100644 miniz-sys-0.1.10/build.rs create mode 100644 miniz-sys-0.1.10/lib.rs create mode 100644 miniz-sys-0.1.10/miniz.c create mode 100644 num-0.1.41/.cargo-checksum.json create mode 100644 num-0.1.41/.travis.yml create mode 100644 num-0.1.41/Cargo.toml create mode 100644 num-0.1.41/LICENSE-APACHE create mode 100644 num-0.1.41/LICENSE-MIT create mode 100644 num-0.1.41/README.md create mode 100644 num-0.1.41/benches/bigint.rs create mode 100644 num-0.1.41/benches/shootout-pidigits.rs create mode 100644 num-0.1.41/bors.toml create mode 100644 num-0.1.41/ci/deploy.enc create mode 100755 num-0.1.41/ci/deploy.sh create mode 100755 num-0.1.41/ci/rustup.sh create mode 100755 num-0.1.41/ci/test_full.sh create mode 100644 num-0.1.41/doc/favicon.ico create mode 100644 num-0.1.41/doc/index.html create mode 100644 num-0.1.41/doc/rust-logo-128x128-blk-v2.png create mode 100644 num-0.1.41/src/lib.rs create mode 100644 num-bigint-0.1.41/.cargo-checksum.json create mode 100644 num-bigint-0.1.41/Cargo.toml create mode 100644 num-bigint-0.1.41/LICENSE-APACHE create mode 100644 num-bigint-0.1.41/LICENSE-MIT create mode 100644 num-bigint-0.1.41/src/algorithms.rs create mode 100644 num-bigint-0.1.41/src/bigint.rs create mode 100644 num-bigint-0.1.41/src/biguint.rs create mode 100644 num-bigint-0.1.41/src/lib.rs create mode 100644 num-bigint-0.1.41/src/macros.rs create mode 100644 num-bigint-0.1.41/src/monty.rs create mode 100644 num-bigint-0.1.41/src/tests/bigint.rs create mode 100644 num-bigint-0.1.41/src/tests/biguint.rs create mode 100644 num-complex-0.1.41/.cargo-checksum.json create mode 100644 num-complex-0.1.41/Cargo.toml create mode 100644 num-complex-0.1.41/LICENSE-APACHE create mode 100644 num-complex-0.1.41/LICENSE-MIT create mode 100644 num-complex-0.1.41/src/lib.rs create mode 100644 num-integer-0.1.35/.cargo-checksum.json create mode 100644 num-integer-0.1.35/Cargo.toml create mode 100644 num-integer-0.1.35/LICENSE-APACHE create mode 100644 num-integer-0.1.35/LICENSE-MIT create mode 100644 num-integer-0.1.35/src/lib.rs create mode 100644 num-iter-0.1.34/.cargo-checksum.json create mode 100644 num-iter-0.1.34/Cargo.toml create mode 100644 num-iter-0.1.34/LICENSE-APACHE create mode 100644 num-iter-0.1.34/LICENSE-MIT create mode 100644 num-iter-0.1.34/src/lib.rs create mode 100644 num-rational-0.1.40/.cargo-checksum.json create mode 100644 num-rational-0.1.40/Cargo.toml create mode 100644 num-rational-0.1.40/LICENSE-APACHE create mode 100644 num-rational-0.1.40/LICENSE-MIT create mode 100644 num-rational-0.1.40/src/lib.rs create mode 100644 num-traits-0.1.41/.cargo-checksum.json create mode 100644 num-traits-0.1.41/Cargo.toml create mode 100644 num-traits-0.1.41/LICENSE-APACHE create mode 100644 num-traits-0.1.41/LICENSE-MIT create mode 100644 num-traits-0.1.41/src/bounds.rs create mode 100644 num-traits-0.1.41/src/cast.rs create mode 100644 num-traits-0.1.41/src/float.rs create mode 100644 num-traits-0.1.41/src/identities.rs create mode 100644 num-traits-0.1.41/src/int.rs create mode 100644 num-traits-0.1.41/src/lib.rs create mode 100644 num-traits-0.1.41/src/ops/checked.rs create mode 100644 num-traits-0.1.41/src/ops/mod.rs create mode 100644 num-traits-0.1.41/src/ops/saturating.rs create mode 100644 num-traits-0.1.41/src/ops/wrapping.rs create mode 100644 num-traits-0.1.41/src/pow.rs create mode 100644 num-traits-0.1.41/src/sign.rs create mode 100644 num_cpus-1.8.0/.appveyor.yml create mode 100644 num_cpus-1.8.0/.cargo-checksum.json create mode 100644 num_cpus-1.8.0/.travis.yml create mode 100644 num_cpus-1.8.0/CHANGELOG.md create mode 100644 num_cpus-1.8.0/CONTRIBUTING.md create mode 100644 num_cpus-1.8.0/Cargo.toml create mode 100644 num_cpus-1.8.0/LICENSE-APACHE create mode 100644 num_cpus-1.8.0/LICENSE-MIT create mode 100644 num_cpus-1.8.0/README.md create mode 100644 num_cpus-1.8.0/src/lib.rs create mode 100644 openssl-0.9.23/.cargo-checksum.json create mode 100644 openssl-0.9.23/Cargo.toml create mode 100644 openssl-0.9.23/LICENSE create mode 100644 openssl-0.9.23/README.md create mode 100644 openssl-0.9.23/build.rs create mode 100644 openssl-0.9.23/examples/mk_certs.rs create mode 100644 openssl-0.9.23/src/aes.rs create mode 100644 openssl-0.9.23/src/asn1.rs create mode 100644 openssl-0.9.23/src/bio.rs create mode 100644 openssl-0.9.23/src/bn.rs create mode 100644 openssl-0.9.23/src/cms.rs create mode 100644 openssl-0.9.23/src/conf.rs create mode 100644 openssl-0.9.23/src/crypto.rs create mode 100644 openssl-0.9.23/src/dh.rs create mode 100644 openssl-0.9.23/src/dsa.rs create mode 100644 openssl-0.9.23/src/ec.rs create mode 100644 openssl-0.9.23/src/ec_key.rs create mode 100644 openssl-0.9.23/src/error.rs create mode 100644 openssl-0.9.23/src/ex_data.rs create mode 100644 openssl-0.9.23/src/hash.rs create mode 100644 openssl-0.9.23/src/lib.rs create mode 100644 openssl-0.9.23/src/macros.rs create mode 100644 openssl-0.9.23/src/memcmp.rs create mode 100644 openssl-0.9.23/src/nid.rs create mode 100644 openssl-0.9.23/src/ocsp.rs create mode 100644 openssl-0.9.23/src/pkcs12.rs create mode 100644 openssl-0.9.23/src/pkcs5.rs create mode 100644 openssl-0.9.23/src/pkey.rs create mode 100644 openssl-0.9.23/src/rand.rs create mode 100644 openssl-0.9.23/src/rsa.rs create mode 100644 openssl-0.9.23/src/sha.rs create mode 100644 openssl-0.9.23/src/sign.rs create mode 100644 openssl-0.9.23/src/ssl/bio.rs create mode 100644 openssl-0.9.23/src/ssl/callbacks.rs create mode 100644 openssl-0.9.23/src/ssl/connector.rs create mode 100644 openssl-0.9.23/src/ssl/error.rs create mode 100644 openssl-0.9.23/src/ssl/mod.rs create mode 100644 openssl-0.9.23/src/ssl/tests/mod.rs create mode 100644 openssl-0.9.23/src/ssl/tests/select.rs create mode 100644 openssl-0.9.23/src/stack.rs create mode 100644 openssl-0.9.23/src/string.rs create mode 100644 openssl-0.9.23/src/symm.rs create mode 100644 openssl-0.9.23/src/types.rs create mode 100644 openssl-0.9.23/src/util.rs create mode 100644 openssl-0.9.23/src/verify.rs create mode 100644 openssl-0.9.23/src/version.rs create mode 100644 openssl-0.9.23/src/x509/extension.rs create mode 100644 openssl-0.9.23/src/x509/mod.rs create mode 100644 openssl-0.9.23/src/x509/store.rs create mode 100644 openssl-0.9.23/src/x509/tests.rs create mode 100644 openssl-0.9.23/src/x509/verify.rs create mode 100644 openssl-0.9.23/test/alt_name_cert.pem create mode 100644 openssl-0.9.23/test/cert.pem create mode 100644 openssl-0.9.23/test/certs.pem create mode 100644 openssl-0.9.23/test/dhparams.pem create mode 100644 openssl-0.9.23/test/dsa-encrypted.pem create mode 100644 openssl-0.9.23/test/dsa.pem create mode 100644 openssl-0.9.23/test/dsa.pem.pub create mode 100644 openssl-0.9.23/test/dsaparam.pem create mode 100644 openssl-0.9.23/test/identity.p12 create mode 100644 openssl-0.9.23/test/key.der create mode 100644 openssl-0.9.23/test/key.der.pub create mode 100644 openssl-0.9.23/test/key.pem create mode 100644 openssl-0.9.23/test/key.pem.pub create mode 100644 openssl-0.9.23/test/keystore-empty-chain.p12 create mode 100644 openssl-0.9.23/test/nid_test_cert.pem create mode 100644 openssl-0.9.23/test/nid_uid_test_cert.pem create mode 100644 openssl-0.9.23/test/pkcs8.der create mode 100644 openssl-0.9.23/test/root-ca.key create mode 100644 openssl-0.9.23/test/root-ca.pem create mode 100644 openssl-0.9.23/test/rsa-encrypted.pem create mode 100644 openssl-0.9.23/test/rsa.pem create mode 100644 openssl-0.9.23/test/rsa.pem.pub create mode 100644 openssl-probe-0.1.2/.cargo-checksum.json create mode 100644 openssl-probe-0.1.2/Cargo.toml create mode 100644 openssl-probe-0.1.2/LICENSE-APACHE create mode 100644 openssl-probe-0.1.2/LICENSE-MIT create mode 100644 openssl-probe-0.1.2/README.md create mode 100644 openssl-probe-0.1.2/src/lib.rs create mode 100644 openssl-sys-0.9.23/.cargo-checksum.json create mode 100644 openssl-sys-0.9.23/Cargo.toml create mode 100644 openssl-sys-0.9.23/LICENSE-MIT create mode 100644 openssl-sys-0.9.23/README.md create mode 100644 openssl-sys-0.9.23/build.rs create mode 100644 openssl-sys-0.9.23/src/lib.rs create mode 100644 openssl-sys-0.9.23/src/libressl/mod.rs create mode 100644 openssl-sys-0.9.23/src/libressl/v250.rs create mode 100644 openssl-sys-0.9.23/src/libressl/v25x.rs create mode 100644 openssl-sys-0.9.23/src/ossl10x.rs create mode 100644 openssl-sys-0.9.23/src/ossl110.rs create mode 100644 percent-encoding-1.0.1/.cargo-checksum.json create mode 100644 percent-encoding-1.0.1/Cargo.toml create mode 100644 percent-encoding-1.0.1/LICENSE-APACHE create mode 100644 percent-encoding-1.0.1/LICENSE-MIT create mode 100644 percent-encoding-1.0.1/lib.rs create mode 100644 pkg-config-0.3.9/.cargo-checksum.json create mode 100644 pkg-config-0.3.9/.travis.yml create mode 100644 pkg-config-0.3.9/Cargo.toml create mode 100644 pkg-config-0.3.9/LICENSE-APACHE create mode 100644 pkg-config-0.3.9/LICENSE-MIT create mode 100644 pkg-config-0.3.9/README.md create mode 100644 pkg-config-0.3.9/src/lib.rs create mode 100644 pkg-config-0.3.9/tests/foo.pc create mode 100644 pkg-config-0.3.9/tests/framework.pc create mode 100644 pkg-config-0.3.9/tests/test.rs create mode 100644 quote-0.3.15/.cargo-checksum.json create mode 100644 quote-0.3.15/Cargo.toml create mode 100644 quote-0.3.15/LICENSE-APACHE create mode 100644 quote-0.3.15/LICENSE-MIT create mode 100644 quote-0.3.15/README.md create mode 100644 quote-0.3.15/src/ident.rs create mode 100644 quote-0.3.15/src/lib.rs create mode 100644 quote-0.3.15/src/to_tokens.rs create mode 100644 quote-0.3.15/src/tokens.rs create mode 100644 quote-0.3.15/tests/test.rs create mode 100644 rand-0.3.20/.cargo-checksum.json create mode 100644 rand-0.3.20/.travis.yml create mode 100644 rand-0.3.20/Cargo.toml create mode 100644 rand-0.3.20/LICENSE-APACHE create mode 100644 rand-0.3.20/LICENSE-MIT create mode 100644 rand-0.3.20/README.md create mode 100644 rand-0.3.20/appveyor.yml create mode 100644 rand-0.3.20/benches/bench.rs create mode 100644 rand-0.3.20/benches/distributions/exponential.rs create mode 100644 rand-0.3.20/benches/distributions/gamma.rs create mode 100644 rand-0.3.20/benches/distributions/mod.rs create mode 100644 rand-0.3.20/benches/distributions/normal.rs create mode 100644 rand-0.3.20/src/chacha.rs create mode 100644 rand-0.3.20/src/distributions/exponential.rs create mode 100644 rand-0.3.20/src/distributions/gamma.rs create mode 100644 rand-0.3.20/src/distributions/mod.rs create mode 100644 rand-0.3.20/src/distributions/normal.rs create mode 100644 rand-0.3.20/src/distributions/range.rs create mode 100644 rand-0.3.20/src/distributions/ziggurat_tables.rs create mode 100644 rand-0.3.20/src/isaac.rs create mode 100644 rand-0.3.20/src/lib.rs create mode 100644 rand-0.3.20/src/os.rs create mode 100644 rand-0.3.20/src/rand_impls.rs create mode 100644 rand-0.3.20/src/read.rs create mode 100644 rand-0.3.20/src/reseeding.rs create mode 100644 redox_syscall-0.1.37/.cargo-checksum.json create mode 100644 redox_syscall-0.1.37/Cargo.toml create mode 100644 redox_syscall-0.1.37/LICENSE create mode 100644 redox_syscall-0.1.37/README.md create mode 100644 redox_syscall-0.1.37/rust-toolchain create mode 100644 redox_syscall-0.1.37/src/arch/arm.rs create mode 100644 redox_syscall-0.1.37/src/arch/x86.rs create mode 100644 redox_syscall-0.1.37/src/arch/x86_64.rs create mode 100644 redox_syscall-0.1.37/src/call.rs create mode 100644 redox_syscall-0.1.37/src/data.rs create mode 100644 redox_syscall-0.1.37/src/error.rs create mode 100644 redox_syscall-0.1.37/src/flag.rs create mode 100644 redox_syscall-0.1.37/src/io/dma.rs create mode 100644 redox_syscall-0.1.37/src/io/io.rs create mode 100644 redox_syscall-0.1.37/src/io/mmio.rs create mode 100644 redox_syscall-0.1.37/src/io/mod.rs create mode 100644 redox_syscall-0.1.37/src/io/pio.rs create mode 100644 redox_syscall-0.1.37/src/lib.rs create mode 100644 redox_syscall-0.1.37/src/number.rs create mode 100644 redox_syscall-0.1.37/src/scheme.rs create mode 100644 redox_termios-0.1.1/.cargo-checksum.json create mode 100644 redox_termios-0.1.1/Cargo.toml create mode 100644 redox_termios-0.1.1/LICENSE create mode 100644 redox_termios-0.1.1/README.md create mode 100644 redox_termios-0.1.1/src/lib.rs create mode 100644 regex-0.1.80/.cargo-checksum.json create mode 100644 regex-0.1.80/.travis.yml create mode 100644 regex-0.1.80/CHANGELOG.md create mode 100644 regex-0.1.80/Cargo.toml create mode 100644 regex-0.1.80/HACKING.md create mode 100644 regex-0.1.80/LICENSE-APACHE create mode 100644 regex-0.1.80/LICENSE-MIT create mode 100644 regex-0.1.80/PERFORMANCE.md create mode 100644 regex-0.1.80/README.md create mode 100644 regex-0.1.80/appveyor.yml create mode 100644 regex-0.1.80/examples/regexdna-input.txt create mode 100644 regex-0.1.80/examples/regexdna-output.txt create mode 100644 regex-0.1.80/examples/shootout-regex-dna-bytes.rs create mode 100644 regex-0.1.80/examples/shootout-regex-dna-cheat.rs create mode 100644 regex-0.1.80/examples/shootout-regex-dna-replace.rs create mode 100644 regex-0.1.80/examples/shootout-regex-dna-single-cheat.rs create mode 100644 regex-0.1.80/examples/shootout-regex-dna-single.rs create mode 100644 regex-0.1.80/examples/shootout-regex-dna.rs create mode 100755 regex-0.1.80/run-kcov create mode 100755 regex-0.1.80/run-shootout-test create mode 100755 regex-0.1.80/scripts/frequencies.py create mode 100755 regex-0.1.80/scripts/regex-match-tests.py create mode 100755 regex-0.1.80/scripts/unicode.py create mode 100644 regex-0.1.80/src/backtrack.rs create mode 100644 regex-0.1.80/src/compile.rs create mode 100644 regex-0.1.80/src/dfa.rs create mode 100644 regex-0.1.80/src/error.rs create mode 100644 regex-0.1.80/src/exec.rs create mode 100644 regex-0.1.80/src/expand.rs create mode 100644 regex-0.1.80/src/freqs.rs create mode 100644 regex-0.1.80/src/input.rs create mode 100644 regex-0.1.80/src/lib.rs create mode 100644 regex-0.1.80/src/literals.rs create mode 100644 regex-0.1.80/src/pattern.rs create mode 100644 regex-0.1.80/src/pikevm.rs create mode 100644 regex-0.1.80/src/prog.rs create mode 100644 regex-0.1.80/src/re_builder.rs create mode 100644 regex-0.1.80/src/re_bytes.rs create mode 100644 regex-0.1.80/src/re_plugin.rs create mode 100644 regex-0.1.80/src/re_set.rs create mode 100644 regex-0.1.80/src/re_trait.rs create mode 100644 regex-0.1.80/src/re_unicode.rs create mode 100644 regex-0.1.80/src/simd_accel/mod.rs create mode 100644 regex-0.1.80/src/simd_accel/teddy128.rs create mode 100644 regex-0.1.80/src/simd_fallback/mod.rs create mode 100644 regex-0.1.80/src/simd_fallback/teddy128.rs create mode 100644 regex-0.1.80/src/sparse.rs create mode 100644 regex-0.1.80/src/testdata/LICENSE create mode 100644 regex-0.1.80/src/testdata/README create mode 100644 regex-0.1.80/src/testdata/basic.dat create mode 100644 regex-0.1.80/src/testdata/nullsubexpr.dat create mode 100644 regex-0.1.80/src/testdata/repetition.dat create mode 100644 regex-0.1.80/src/utf8.rs create mode 100644 regex-0.1.80/tests/api.rs create mode 100644 regex-0.1.80/tests/api_str.rs create mode 100644 regex-0.1.80/tests/bytes.rs create mode 100644 regex-0.1.80/tests/crazy.rs create mode 100644 regex-0.1.80/tests/flags.rs create mode 100644 regex-0.1.80/tests/fowler.rs create mode 100644 regex-0.1.80/tests/macros.rs create mode 100644 regex-0.1.80/tests/macros_bytes.rs create mode 100644 regex-0.1.80/tests/macros_str.rs create mode 100644 regex-0.1.80/tests/misc.rs create mode 100644 regex-0.1.80/tests/multiline.rs create mode 100644 regex-0.1.80/tests/noparse.rs create mode 100644 regex-0.1.80/tests/plugin.rs create mode 100644 regex-0.1.80/tests/regression.rs create mode 100644 regex-0.1.80/tests/replace.rs create mode 100644 regex-0.1.80/tests/searcher.rs create mode 100644 regex-0.1.80/tests/set.rs create mode 100644 regex-0.1.80/tests/shortest_match.rs create mode 100644 regex-0.1.80/tests/suffix_reverse.rs create mode 100644 regex-0.1.80/tests/test_backtrack.rs create mode 100644 regex-0.1.80/tests/test_backtrack_bytes.rs create mode 100644 regex-0.1.80/tests/test_backtrack_utf8bytes.rs create mode 100644 regex-0.1.80/tests/test_default.rs create mode 100644 regex-0.1.80/tests/test_default_bytes.rs create mode 100644 regex-0.1.80/tests/test_nfa.rs create mode 100644 regex-0.1.80/tests/test_nfa_bytes.rs create mode 100644 regex-0.1.80/tests/test_nfa_utf8bytes.rs create mode 100644 regex-0.1.80/tests/test_plugin.rs create mode 100644 regex-0.1.80/tests/unicode.rs create mode 100644 regex-0.1.80/tests/word_boundary.rs create mode 100644 regex-0.1.80/tests/word_boundary_ascii.rs create mode 100644 regex-0.1.80/tests/word_boundary_unicode.rs create mode 100644 regex-0.2.5/.cargo-checksum.json create mode 100644 regex-0.2.5/.travis.yml create mode 100644 regex-0.2.5/CHANGELOG.md create mode 100644 regex-0.2.5/Cargo.toml create mode 100644 regex-0.2.5/HACKING.md create mode 100644 regex-0.2.5/LICENSE-APACHE create mode 100644 regex-0.2.5/LICENSE-MIT create mode 100644 regex-0.2.5/PERFORMANCE.md create mode 100644 regex-0.2.5/README.md create mode 100644 regex-0.2.5/appveyor.yml create mode 100755 regex-0.2.5/ci/after_success.sh create mode 100755 regex-0.2.5/ci/run-kcov create mode 100755 regex-0.2.5/ci/run-shootout-test create mode 100755 regex-0.2.5/ci/script.sh create mode 100644 regex-0.2.5/examples/regexdna-input.txt create mode 100644 regex-0.2.5/examples/regexdna-output.txt create mode 100644 regex-0.2.5/examples/shootout-regex-dna-bytes.rs create mode 100644 regex-0.2.5/examples/shootout-regex-dna-cheat.rs create mode 100644 regex-0.2.5/examples/shootout-regex-dna-replace.rs create mode 100644 regex-0.2.5/examples/shootout-regex-dna-single-cheat.rs create mode 100644 regex-0.2.5/examples/shootout-regex-dna-single.rs create mode 100644 regex-0.2.5/examples/shootout-regex-dna.rs create mode 100755 regex-0.2.5/scripts/frequencies.py create mode 100755 regex-0.2.5/scripts/regex-match-tests.py create mode 100755 regex-0.2.5/scripts/unicode.py create mode 100644 regex-0.2.5/src/backtrack.rs create mode 100644 regex-0.2.5/src/compile.rs create mode 100644 regex-0.2.5/src/dfa.rs create mode 100644 regex-0.2.5/src/error.rs create mode 100644 regex-0.2.5/src/exec.rs create mode 100644 regex-0.2.5/src/expand.rs create mode 100644 regex-0.2.5/src/freqs.rs create mode 100644 regex-0.2.5/src/input.rs create mode 100644 regex-0.2.5/src/lib.rs create mode 100644 regex-0.2.5/src/literals.rs create mode 100644 regex-0.2.5/src/pattern.rs create mode 100644 regex-0.2.5/src/pikevm.rs create mode 100644 regex-0.2.5/src/prog.rs create mode 100644 regex-0.2.5/src/re_builder.rs create mode 100644 regex-0.2.5/src/re_bytes.rs create mode 100644 regex-0.2.5/src/re_set.rs create mode 100644 regex-0.2.5/src/re_trait.rs create mode 100644 regex-0.2.5/src/re_unicode.rs create mode 100644 regex-0.2.5/src/simd_accel/mod.rs create mode 100644 regex-0.2.5/src/simd_accel/teddy128.rs create mode 100644 regex-0.2.5/src/simd_fallback/mod.rs create mode 100644 regex-0.2.5/src/simd_fallback/teddy128.rs create mode 100644 regex-0.2.5/src/sparse.rs create mode 100644 regex-0.2.5/src/testdata/LICENSE create mode 100644 regex-0.2.5/src/testdata/README create mode 100644 regex-0.2.5/src/testdata/basic.dat create mode 100644 regex-0.2.5/src/testdata/nullsubexpr.dat create mode 100644 regex-0.2.5/src/testdata/repetition.dat create mode 100644 regex-0.2.5/src/utf8.rs create mode 100644 regex-0.2.5/tests/api.rs create mode 100644 regex-0.2.5/tests/api_str.rs create mode 100644 regex-0.2.5/tests/bytes.rs create mode 100644 regex-0.2.5/tests/crazy.rs create mode 100644 regex-0.2.5/tests/flags.rs create mode 100644 regex-0.2.5/tests/fowler.rs create mode 100644 regex-0.2.5/tests/macros.rs create mode 100644 regex-0.2.5/tests/macros_bytes.rs create mode 100644 regex-0.2.5/tests/macros_str.rs create mode 100644 regex-0.2.5/tests/misc.rs create mode 100644 regex-0.2.5/tests/multiline.rs create mode 100644 regex-0.2.5/tests/noparse.rs create mode 100644 regex-0.2.5/tests/plugin.rs create mode 100644 regex-0.2.5/tests/regression.rs create mode 100644 regex-0.2.5/tests/replace.rs create mode 100644 regex-0.2.5/tests/searcher.rs create mode 100644 regex-0.2.5/tests/set.rs create mode 100644 regex-0.2.5/tests/shortest_match.rs create mode 100644 regex-0.2.5/tests/suffix_reverse.rs create mode 100644 regex-0.2.5/tests/test_backtrack.rs create mode 100644 regex-0.2.5/tests/test_backtrack_bytes.rs create mode 100644 regex-0.2.5/tests/test_backtrack_utf8bytes.rs create mode 100644 regex-0.2.5/tests/test_default.rs create mode 100644 regex-0.2.5/tests/test_default_bytes.rs create mode 100644 regex-0.2.5/tests/test_nfa.rs create mode 100644 regex-0.2.5/tests/test_nfa_bytes.rs create mode 100644 regex-0.2.5/tests/test_nfa_utf8bytes.rs create mode 100644 regex-0.2.5/tests/unicode.rs create mode 100644 regex-0.2.5/tests/word_boundary.rs create mode 100644 regex-0.2.5/tests/word_boundary_ascii.rs create mode 100644 regex-0.2.5/tests/word_boundary_unicode.rs create mode 100644 regex-syntax-0.3.9/.cargo-checksum.json create mode 100644 regex-syntax-0.3.9/Cargo.toml create mode 100644 regex-syntax-0.3.9/src/lib.rs create mode 100644 regex-syntax-0.3.9/src/literals.rs create mode 100644 regex-syntax-0.3.9/src/parser.rs create mode 100644 regex-syntax-0.3.9/src/properties.rs create mode 100644 regex-syntax-0.3.9/src/unicode.rs create mode 100644 regex-syntax-0.4.2/.cargo-checksum.json create mode 100644 regex-syntax-0.4.2/Cargo.toml create mode 100644 regex-syntax-0.4.2/src/lib.rs create mode 100644 regex-syntax-0.4.2/src/literals.rs create mode 100644 regex-syntax-0.4.2/src/parser.rs create mode 100644 regex-syntax-0.4.2/src/properties.rs create mode 100644 regex-syntax-0.4.2/src/unicode.rs create mode 100644 rustc-demangle-0.1.5/.cargo-checksum.json create mode 100644 rustc-demangle-0.1.5/.travis.yml create mode 100644 rustc-demangle-0.1.5/Cargo.toml create mode 100644 rustc-demangle-0.1.5/LICENSE-APACHE create mode 100644 rustc-demangle-0.1.5/LICENSE-MIT create mode 100644 rustc-demangle-0.1.5/README.md create mode 100644 rustc-demangle-0.1.5/src/lib.rs create mode 100644 rustc-serialize-0.3.24/.cargo-checksum.json create mode 100644 rustc-serialize-0.3.24/.travis.yml create mode 100644 rustc-serialize-0.3.24/Cargo.toml create mode 100644 rustc-serialize-0.3.24/LICENSE-APACHE create mode 100644 rustc-serialize-0.3.24/LICENSE-MIT create mode 100644 rustc-serialize-0.3.24/README.md create mode 100644 rustc-serialize-0.3.24/appveyor.yml create mode 100644 rustc-serialize-0.3.24/benches/base64.rs create mode 100644 rustc-serialize-0.3.24/benches/hex.rs create mode 100644 rustc-serialize-0.3.24/benches/json.rs create mode 100644 rustc-serialize-0.3.24/src/base64.rs create mode 100644 rustc-serialize-0.3.24/src/collection_impls.rs create mode 100644 rustc-serialize-0.3.24/src/hex.rs create mode 100644 rustc-serialize-0.3.24/src/json.rs create mode 100644 rustc-serialize-0.3.24/src/lib.rs create mode 100644 rustc-serialize-0.3.24/src/serialize.rs create mode 100644 same-file-0.1.3/.cargo-checksum.json create mode 100644 same-file-0.1.3/.travis.yml create mode 100644 same-file-0.1.3/COPYING create mode 100644 same-file-0.1.3/Cargo.toml create mode 100644 same-file-0.1.3/README.md create mode 100644 same-file-0.1.3/appveyor.yml create mode 100644 same-file-0.1.3/examples/is_same_file.rs create mode 100644 same-file-0.1.3/examples/is_stderr.rs create mode 100644 same-file-0.1.3/src/lib.rs create mode 100644 same-file-0.1.3/src/unix.rs create mode 100644 same-file-0.1.3/src/win.rs create mode 100644 schannel-0.1.9/.cargo-checksum.json create mode 100644 schannel-0.1.9/Cargo.toml create mode 100644 schannel-0.1.9/LICENSE.md create mode 100644 schannel-0.1.9/README.md create mode 100644 schannel-0.1.9/appveyor.yml create mode 100644 schannel-0.1.9/build.rs create mode 100644 schannel-0.1.9/src/cert_chain.rs create mode 100644 schannel-0.1.9/src/cert_context.rs create mode 100644 schannel-0.1.9/src/cert_store.rs create mode 100644 schannel-0.1.9/src/context_buffer.rs create mode 100644 schannel-0.1.9/src/crypt_key.rs create mode 100644 schannel-0.1.9/src/crypt_prov.rs create mode 100644 schannel-0.1.9/src/ctl_context.rs create mode 100644 schannel-0.1.9/src/key_handle.rs create mode 100644 schannel-0.1.9/src/lib.rs create mode 100644 schannel-0.1.9/src/ncrypt_key.rs create mode 100644 schannel-0.1.9/src/schannel_cred.rs create mode 100644 schannel-0.1.9/src/security_context.rs create mode 100644 schannel-0.1.9/src/test.rs create mode 100644 schannel-0.1.9/src/tls_stream.rs create mode 100644 schannel-0.1.9/test/cert.der create mode 100644 schannel-0.1.9/test/cert.pem create mode 100644 schannel-0.1.9/test/identity.p12 create mode 100644 schannel-0.1.9/test/key.key create mode 100644 schannel-0.1.9/test/key.pem create mode 100644 schannel-0.1.9/test/self-signed.badssl.com.cer create mode 100644 scoped-tls-0.1.0/.cargo-checksum.json create mode 100644 scoped-tls-0.1.0/.travis.yml create mode 100644 scoped-tls-0.1.0/Cargo.toml create mode 100644 scoped-tls-0.1.0/LICENSE-APACHE create mode 100644 scoped-tls-0.1.0/LICENSE-MIT create mode 100644 scoped-tls-0.1.0/README.md create mode 100644 scoped-tls-0.1.0/appveyor.yml create mode 100644 scoped-tls-0.1.0/src/lib.rs create mode 100644 scopeguard-0.1.2/.cargo-checksum.json create mode 100644 scopeguard-0.1.2/.travis.yml create mode 100644 scopeguard-0.1.2/Cargo.toml create mode 100644 scopeguard-0.1.2/LICENSE-APACHE create mode 100644 scopeguard-0.1.2/LICENSE-MIT create mode 100644 scopeguard-0.1.2/README.rst create mode 100644 scopeguard-0.1.2/src/lib.rs create mode 100644 secur32-sys-0.2.0/.cargo-checksum.json create mode 100644 secur32-sys-0.2.0/Cargo.toml create mode 100644 secur32-sys-0.2.0/README.md create mode 100644 secur32-sys-0.2.0/build.rs create mode 100644 secur32-sys-0.2.0/src/lib.rs create mode 100644 semver-0.8.0/.cargo-checksum.json create mode 100644 semver-0.8.0/.travis.yml create mode 100644 semver-0.8.0/Cargo.toml create mode 100644 semver-0.8.0/LICENSE-APACHE create mode 100644 semver-0.8.0/LICENSE-MIT create mode 100644 semver-0.8.0/README.md create mode 100644 semver-0.8.0/src/lib.rs create mode 100644 semver-0.8.0/src/version.rs create mode 100644 semver-0.8.0/src/version_req.rs create mode 100644 semver-0.8.0/tests/deprecation.rs create mode 100644 semver-0.8.0/tests/regression.rs create mode 100644 semver-0.8.0/tests/serde.rs create mode 100644 semver-parser-0.7.0/.cargo-checksum.json create mode 100644 semver-parser-0.7.0/Cargo.toml create mode 100644 semver-parser-0.7.0/LICENSE-APACHE create mode 100644 semver-parser-0.7.0/LICENSE-MIT create mode 100644 semver-parser-0.7.0/src/common.rs create mode 100644 semver-parser-0.7.0/src/lib.rs create mode 100644 semver-parser-0.7.0/src/range.rs create mode 100644 semver-parser-0.7.0/src/recognize.rs create mode 100644 semver-parser-0.7.0/src/version.rs create mode 100644 serde-1.0.27/.cargo-checksum.json create mode 100644 serde-1.0.27/Cargo.toml create mode 100644 serde-1.0.27/LICENSE-APACHE create mode 100644 serde-1.0.27/LICENSE-MIT create mode 100644 serde-1.0.27/README.md create mode 100644 serde-1.0.27/src/de/from_primitive.rs create mode 100644 serde-1.0.27/src/de/ignored_any.rs create mode 100644 serde-1.0.27/src/de/impls.rs create mode 100644 serde-1.0.27/src/de/mod.rs create mode 100644 serde-1.0.27/src/de/utf8.rs create mode 100644 serde-1.0.27/src/de/value.rs create mode 100644 serde-1.0.27/src/export.rs create mode 100644 serde-1.0.27/src/lib.rs create mode 100644 serde-1.0.27/src/macros.rs create mode 100644 serde-1.0.27/src/private/de.rs create mode 100644 serde-1.0.27/src/private/macros.rs create mode 100644 serde-1.0.27/src/private/mod.rs create mode 100644 serde-1.0.27/src/private/ser.rs create mode 100644 serde-1.0.27/src/ser/impls.rs create mode 100644 serde-1.0.27/src/ser/impossible.rs create mode 100644 serde-1.0.27/src/ser/mod.rs create mode 100644 serde_derive-1.0.27/.cargo-checksum.json create mode 100644 serde_derive-1.0.27/Cargo.toml create mode 100644 serde_derive-1.0.27/LICENSE-APACHE create mode 100644 serde_derive-1.0.27/LICENSE-MIT create mode 100644 serde_derive-1.0.27/README.md create mode 100644 serde_derive-1.0.27/src/bound.rs create mode 100644 serde_derive-1.0.27/src/de.rs create mode 100644 serde_derive-1.0.27/src/fragment.rs create mode 100644 serde_derive-1.0.27/src/lib.rs create mode 100644 serde_derive-1.0.27/src/ser.rs create mode 100644 serde_derive_internals-0.19.0/.cargo-checksum.json create mode 100644 serde_derive_internals-0.19.0/Cargo.toml create mode 100644 serde_derive_internals-0.19.0/LICENSE-APACHE create mode 100644 serde_derive_internals-0.19.0/LICENSE-MIT create mode 100644 serde_derive_internals-0.19.0/README.md create mode 100644 serde_derive_internals-0.19.0/src/ast.rs create mode 100644 serde_derive_internals-0.19.0/src/attr.rs create mode 100644 serde_derive_internals-0.19.0/src/case.rs create mode 100644 serde_derive_internals-0.19.0/src/check.rs create mode 100644 serde_derive_internals-0.19.0/src/ctxt.rs create mode 100644 serde_derive_internals-0.19.0/src/lib.rs create mode 100644 serde_ignored-0.0.4/.cargo-checksum.json create mode 100644 serde_ignored-0.0.4/.travis.yml create mode 100644 serde_ignored-0.0.4/Cargo.toml create mode 100644 serde_ignored-0.0.4/LICENSE-APACHE create mode 100644 serde_ignored-0.0.4/LICENSE-MIT create mode 100644 serde_ignored-0.0.4/README.md create mode 100644 serde_ignored-0.0.4/src/lib.rs create mode 100644 serde_json-1.0.9/.cargo-checksum.json create mode 100644 serde_json-1.0.9/Cargo.toml create mode 100644 serde_json-1.0.9/LICENSE-APACHE create mode 100644 serde_json-1.0.9/LICENSE-MIT create mode 100644 serde_json-1.0.9/README.md create mode 100644 serde_json-1.0.9/src/de.rs create mode 100644 serde_json-1.0.9/src/error.rs create mode 100644 serde_json-1.0.9/src/iter.rs create mode 100644 serde_json-1.0.9/src/lib.rs create mode 100644 serde_json-1.0.9/src/macros.rs create mode 100644 serde_json-1.0.9/src/map.rs create mode 100644 serde_json-1.0.9/src/number.rs create mode 100644 serde_json-1.0.9/src/read.rs create mode 100644 serde_json-1.0.9/src/ser.rs create mode 100644 serde_json-1.0.9/src/value/de.rs create mode 100644 serde_json-1.0.9/src/value/from.rs create mode 100644 serde_json-1.0.9/src/value/index.rs create mode 100644 serde_json-1.0.9/src/value/mod.rs create mode 100644 serde_json-1.0.9/src/value/partial_eq.rs create mode 100644 serde_json-1.0.9/src/value/ser.rs create mode 100644 shell-escape-0.1.3/.cargo-checksum.json create mode 100644 shell-escape-0.1.3/.travis.yml create mode 100644 shell-escape-0.1.3/Cargo.toml create mode 100644 shell-escape-0.1.3/LICENSE-APACHE create mode 100644 shell-escape-0.1.3/LICENSE-MIT create mode 100644 shell-escape-0.1.3/README.md create mode 100644 shell-escape-0.1.3/src/lib.rs create mode 100644 socket2-0.3.0/.appveyor.yml create mode 100644 socket2-0.3.0/.cargo-checksum.json create mode 100644 socket2-0.3.0/.travis.yml create mode 100644 socket2-0.3.0/Cargo.toml create mode 100644 socket2-0.3.0/LICENSE-APACHE create mode 100644 socket2-0.3.0/LICENSE-MIT create mode 100644 socket2-0.3.0/README.md create mode 100644 socket2-0.3.0/src/lib.rs create mode 100644 socket2-0.3.0/src/sockaddr.rs create mode 100644 socket2-0.3.0/src/socket.rs create mode 100644 socket2-0.3.0/src/sys/unix/mod.rs create mode 100644 socket2-0.3.0/src/sys/unix/weak.rs create mode 100644 socket2-0.3.0/src/sys/windows.rs create mode 100644 socket2-0.3.0/src/utils.rs create mode 100644 strsim-0.6.0/.cargo-checksum.json create mode 100644 strsim-0.6.0/.editorconfig create mode 100644 strsim-0.6.0/.travis.yml create mode 100644 strsim-0.6.0/CHANGELOG.md create mode 100644 strsim-0.6.0/Cargo.toml create mode 100644 strsim-0.6.0/LICENSE create mode 100644 strsim-0.6.0/README.md create mode 100644 strsim-0.6.0/appveyor.yml create mode 100755 strsim-0.6.0/dev create mode 100644 strsim-0.6.0/src/lib.rs create mode 100644 strsim-0.6.0/tests/lib.rs create mode 100644 syn-0.11.11/.cargo-checksum.json create mode 100644 syn-0.11.11/Cargo.toml create mode 100644 syn-0.11.11/LICENSE-APACHE create mode 100644 syn-0.11.11/LICENSE-MIT create mode 100644 syn-0.11.11/README.md create mode 100644 syn-0.11.11/src/aster/generics.rs create mode 100644 syn-0.11.11/src/aster/ident.rs create mode 100644 syn-0.11.11/src/aster/invoke.rs create mode 100644 syn-0.11.11/src/aster/lifetime.rs create mode 100644 syn-0.11.11/src/aster/mod.rs create mode 100644 syn-0.11.11/src/aster/path.rs create mode 100644 syn-0.11.11/src/aster/qpath.rs create mode 100644 syn-0.11.11/src/aster/ty.rs create mode 100644 syn-0.11.11/src/aster/ty_param.rs create mode 100644 syn-0.11.11/src/aster/where_predicate.rs create mode 100644 syn-0.11.11/src/attr.rs create mode 100644 syn-0.11.11/src/constant.rs create mode 100644 syn-0.11.11/src/data.rs create mode 100644 syn-0.11.11/src/derive.rs create mode 100644 syn-0.11.11/src/escape.rs create mode 100644 syn-0.11.11/src/expr.rs create mode 100644 syn-0.11.11/src/fold.rs create mode 100644 syn-0.11.11/src/generics.rs create mode 100644 syn-0.11.11/src/ident.rs create mode 100644 syn-0.11.11/src/item.rs create mode 100644 syn-0.11.11/src/krate.rs create mode 100644 syn-0.11.11/src/lib.rs create mode 100644 syn-0.11.11/src/lit.rs create mode 100644 syn-0.11.11/src/mac.rs create mode 100644 syn-0.11.11/src/op.rs create mode 100644 syn-0.11.11/src/ty.rs create mode 100644 syn-0.11.11/src/visit.rs create mode 100644 synom-0.11.3/.cargo-checksum.json create mode 100644 synom-0.11.3/Cargo.toml create mode 100644 synom-0.11.3/LICENSE-APACHE create mode 100644 synom-0.11.3/LICENSE-MIT create mode 100644 synom-0.11.3/README.md create mode 100644 synom-0.11.3/src/helper.rs create mode 100644 synom-0.11.3/src/lib.rs create mode 100644 synom-0.11.3/src/space.rs create mode 100644 tar-0.4.14/.cargo-checksum.json create mode 100644 tar-0.4.14/.travis.yml create mode 100644 tar-0.4.14/Cargo.toml create mode 100644 tar-0.4.14/LICENSE-APACHE create mode 100644 tar-0.4.14/LICENSE-MIT create mode 100644 tar-0.4.14/README.md create mode 100644 tar-0.4.14/appveyor.yml create mode 100644 tar-0.4.14/examples/extract_file.rs create mode 100644 tar-0.4.14/examples/list.rs create mode 100644 tar-0.4.14/examples/raw_list.rs create mode 100644 tar-0.4.14/examples/write.rs create mode 100644 tar-0.4.14/src/archive.rs create mode 100644 tar-0.4.14/src/builder.rs create mode 100644 tar-0.4.14/src/entry.rs create mode 100644 tar-0.4.14/src/entry_type.rs create mode 100644 tar-0.4.14/src/error.rs create mode 100644 tar-0.4.14/src/header.rs create mode 100644 tar-0.4.14/src/lib.rs create mode 100644 tar-0.4.14/src/pax.rs create mode 100644 tar-0.4.14/tests/all.rs create mode 100644 tar-0.4.14/tests/archives/directory.tar create mode 100644 tar-0.4.14/tests/archives/duplicate_dirs.tar create mode 100644 tar-0.4.14/tests/archives/empty_filename.tar create mode 100644 tar-0.4.14/tests/archives/file_times.tar create mode 100644 tar-0.4.14/tests/archives/link.tar create mode 100644 tar-0.4.14/tests/archives/pax.tar create mode 100644 tar-0.4.14/tests/archives/reading_files.tar create mode 100644 tar-0.4.14/tests/archives/simple.tar create mode 100755 tar-0.4.14/tests/archives/spaces.tar create mode 100644 tar-0.4.14/tests/archives/sparse.tar create mode 100644 tar-0.4.14/tests/archives/xattrs.tar create mode 100644 tar-0.4.14/tests/entry.rs create mode 100644 tar-0.4.14/tests/header/mod.rs create mode 100644 tempdir-0.3.5/.cargo-checksum.json create mode 100644 tempdir-0.3.5/.travis.yml create mode 100644 tempdir-0.3.5/Cargo.toml create mode 100644 tempdir-0.3.5/LICENSE-APACHE create mode 100644 tempdir-0.3.5/LICENSE-MIT create mode 100644 tempdir-0.3.5/README.md create mode 100644 tempdir-0.3.5/src/lib.rs create mode 100644 tempdir-0.3.5/tests/smoke.rs create mode 100644 termcolor-0.3.3/.cargo-checksum.json create mode 100644 termcolor-0.3.3/COPYING create mode 100644 termcolor-0.3.3/Cargo.toml create mode 100644 termcolor-0.3.3/LICENSE-MIT create mode 100644 termcolor-0.3.3/README.md create mode 100644 termcolor-0.3.3/UNLICENSE create mode 100644 termcolor-0.3.3/src/lib.rs create mode 100644 termion-1.5.1/.cargo-checksum.json create mode 100644 termion-1.5.1/.travis.yml create mode 100644 termion-1.5.1/Cargo.toml create mode 100644 termion-1.5.1/LICENSE create mode 100644 termion-1.5.1/README.md create mode 100644 termion-1.5.1/examples/alternate_screen.rs create mode 100644 termion-1.5.1/examples/alternate_screen_raw.rs create mode 100644 termion-1.5.1/examples/async.rs create mode 100644 termion-1.5.1/examples/click.rs create mode 100644 termion-1.5.1/examples/color.rs create mode 100644 termion-1.5.1/examples/commie.rs create mode 100644 termion-1.5.1/examples/detect_color.rs create mode 100644 termion-1.5.1/examples/is_tty.rs create mode 100644 termion-1.5.1/examples/keys.rs create mode 100644 termion-1.5.1/examples/mouse.rs create mode 100644 termion-1.5.1/examples/rainbow.rs create mode 100644 termion-1.5.1/examples/read.rs create mode 100644 termion-1.5.1/examples/rustc_fun.rs create mode 100644 termion-1.5.1/examples/simple.rs create mode 100644 termion-1.5.1/examples/size.rs create mode 100644 termion-1.5.1/examples/truecolor.rs create mode 100644 termion-1.5.1/logo.svg create mode 100644 termion-1.5.1/src/async.rs create mode 100644 termion-1.5.1/src/clear.rs create mode 100644 termion-1.5.1/src/color.rs create mode 100644 termion-1.5.1/src/cursor.rs create mode 100644 termion-1.5.1/src/event.rs create mode 100644 termion-1.5.1/src/input.rs create mode 100644 termion-1.5.1/src/lib.rs create mode 100644 termion-1.5.1/src/macros.rs create mode 100644 termion-1.5.1/src/raw.rs create mode 100644 termion-1.5.1/src/screen.rs create mode 100644 termion-1.5.1/src/scroll.rs create mode 100644 termion-1.5.1/src/style.rs create mode 100644 termion-1.5.1/src/sys/redox/attr.rs create mode 100644 termion-1.5.1/src/sys/redox/mod.rs create mode 100644 termion-1.5.1/src/sys/redox/size.rs create mode 100644 termion-1.5.1/src/sys/redox/tty.rs create mode 100644 termion-1.5.1/src/sys/unix/attr.rs create mode 100644 termion-1.5.1/src/sys/unix/mod.rs create mode 100644 termion-1.5.1/src/sys/unix/size.rs create mode 100644 termion-1.5.1/src/sys/unix/tty.rs create mode 100644 thread-id-2.0.0/.appveyor.yml create mode 100644 thread-id-2.0.0/.cargo-checksum.json create mode 100644 thread-id-2.0.0/.travis.yml create mode 100644 thread-id-2.0.0/Cargo.toml create mode 100644 thread-id-2.0.0/license create mode 100644 thread-id-2.0.0/readme.md create mode 100644 thread-id-2.0.0/src/lib.rs create mode 100644 thread_local-0.2.7/.cargo-checksum.json create mode 100644 thread_local-0.2.7/.travis.yml create mode 100644 thread_local-0.2.7/Cargo.toml create mode 100644 thread_local-0.2.7/LICENSE-APACHE create mode 100644 thread_local-0.2.7/LICENSE-MIT create mode 100644 thread_local-0.2.7/README.md create mode 100644 thread_local-0.2.7/src/lib.rs create mode 100644 thread_local-0.3.5/.cargo-checksum.json create mode 100644 thread_local-0.3.5/.travis.yml create mode 100644 thread_local-0.3.5/Cargo.toml create mode 100644 thread_local-0.3.5/LICENSE-APACHE create mode 100644 thread_local-0.3.5/LICENSE-MIT create mode 100644 thread_local-0.3.5/README.md create mode 100644 thread_local-0.3.5/benches/thread_local.rs create mode 100644 thread_local-0.3.5/src/lib.rs create mode 100644 thread_local-0.3.5/src/thread_id.rs create mode 100644 toml-0.4.5/.cargo-checksum.json create mode 100644 toml-0.4.5/.travis.yml create mode 100644 toml-0.4.5/Cargo.toml create mode 100644 toml-0.4.5/LICENSE-APACHE create mode 100644 toml-0.4.5/LICENSE-MIT create mode 100644 toml-0.4.5/README.md create mode 100644 toml-0.4.5/examples/decode.rs create mode 100644 toml-0.4.5/examples/toml2json.rs create mode 100644 toml-0.4.5/src/datetime.rs create mode 100644 toml-0.4.5/src/de.rs create mode 100644 toml-0.4.5/src/lib.rs create mode 100644 toml-0.4.5/src/ser.rs create mode 100644 toml-0.4.5/src/tokens.rs create mode 100644 toml-0.4.5/src/value.rs create mode 100644 toml-0.4.5/tests/README.md create mode 100644 toml-0.4.5/tests/backcompat.rs create mode 100644 toml-0.4.5/tests/datetime.rs create mode 100644 toml-0.4.5/tests/display-tricky.rs create mode 100644 toml-0.4.5/tests/display.rs create mode 100644 toml-0.4.5/tests/formatting.rs create mode 100644 toml-0.4.5/tests/invalid-encoder-misc.rs create mode 100644 toml-0.4.5/tests/invalid-encoder/array-mixed-types-ints-and-floats.json create mode 100644 toml-0.4.5/tests/invalid-misc.rs create mode 100644 toml-0.4.5/tests/invalid.rs create mode 100644 toml-0.4.5/tests/invalid/array-mixed-types-arrays-and-ints.toml create mode 100644 toml-0.4.5/tests/invalid/array-mixed-types-ints-and-floats.toml create mode 100644 toml-0.4.5/tests/invalid/array-mixed-types-strings-and-ints.toml create mode 100644 toml-0.4.5/tests/invalid/datetime-malformed-no-leads.toml create mode 100644 toml-0.4.5/tests/invalid/datetime-malformed-no-secs.toml create mode 100644 toml-0.4.5/tests/invalid/datetime-malformed-no-t.toml create mode 100644 toml-0.4.5/tests/invalid/datetime-malformed-with-milli.toml create mode 100644 toml-0.4.5/tests/invalid/duplicate-key-table.toml create mode 100644 toml-0.4.5/tests/invalid/duplicate-keys.toml create mode 100644 toml-0.4.5/tests/invalid/duplicate-tables.toml create mode 100644 toml-0.4.5/tests/invalid/empty-implicit-table.toml create mode 100644 toml-0.4.5/tests/invalid/empty-table.toml create mode 100644 toml-0.4.5/tests/invalid/float-no-leading-zero.toml create mode 100644 toml-0.4.5/tests/invalid/float-no-trailing-digits.toml create mode 100644 toml-0.4.5/tests/invalid/key-after-array.toml create mode 100644 toml-0.4.5/tests/invalid/key-after-table.toml create mode 100644 toml-0.4.5/tests/invalid/key-empty.toml create mode 100644 toml-0.4.5/tests/invalid/key-hash.toml create mode 100644 toml-0.4.5/tests/invalid/key-newline.toml create mode 100644 toml-0.4.5/tests/invalid/key-open-bracket.toml create mode 100644 toml-0.4.5/tests/invalid/key-single-open-bracket.toml create mode 100644 toml-0.4.5/tests/invalid/key-space.toml create mode 100644 toml-0.4.5/tests/invalid/key-start-bracket.toml create mode 100644 toml-0.4.5/tests/invalid/key-two-equals.toml create mode 100644 toml-0.4.5/tests/invalid/string-bad-byte-escape.toml create mode 100644 toml-0.4.5/tests/invalid/string-bad-escape.toml create mode 100644 toml-0.4.5/tests/invalid/string-byte-escapes.toml create mode 100644 toml-0.4.5/tests/invalid/string-no-close.toml create mode 100644 toml-0.4.5/tests/invalid/table-array-implicit.toml create mode 100644 toml-0.4.5/tests/invalid/table-array-malformed-bracket.toml create mode 100644 toml-0.4.5/tests/invalid/table-array-malformed-empty.toml create mode 100644 toml-0.4.5/tests/invalid/table-empty.toml create mode 100644 toml-0.4.5/tests/invalid/table-nested-brackets-close.toml create mode 100644 toml-0.4.5/tests/invalid/table-nested-brackets-open.toml create mode 100644 toml-0.4.5/tests/invalid/table-whitespace.toml create mode 100644 toml-0.4.5/tests/invalid/table-with-pound.toml create mode 100644 toml-0.4.5/tests/invalid/text-after-array-entries.toml create mode 100644 toml-0.4.5/tests/invalid/text-after-integer.toml create mode 100644 toml-0.4.5/tests/invalid/text-after-string.toml create mode 100644 toml-0.4.5/tests/invalid/text-after-table.toml create mode 100644 toml-0.4.5/tests/invalid/text-before-array-separator.toml create mode 100644 toml-0.4.5/tests/invalid/text-in-array.toml create mode 100644 toml-0.4.5/tests/parser.rs create mode 100644 toml-0.4.5/tests/pretty.rs create mode 100644 toml-0.4.5/tests/serde.rs create mode 100644 toml-0.4.5/tests/tables-last.rs create mode 100644 toml-0.4.5/tests/valid.rs create mode 100644 toml-0.4.5/tests/valid/array-empty.json create mode 100644 toml-0.4.5/tests/valid/array-empty.toml create mode 100644 toml-0.4.5/tests/valid/array-nospaces.json create mode 100644 toml-0.4.5/tests/valid/array-nospaces.toml create mode 100644 toml-0.4.5/tests/valid/arrays-hetergeneous.json create mode 100644 toml-0.4.5/tests/valid/arrays-hetergeneous.toml create mode 100644 toml-0.4.5/tests/valid/arrays-nested.json create mode 100644 toml-0.4.5/tests/valid/arrays-nested.toml create mode 100644 toml-0.4.5/tests/valid/arrays.json create mode 100644 toml-0.4.5/tests/valid/arrays.toml create mode 100644 toml-0.4.5/tests/valid/bool.json create mode 100644 toml-0.4.5/tests/valid/bool.toml create mode 100644 toml-0.4.5/tests/valid/comments-everywhere.json create mode 100644 toml-0.4.5/tests/valid/comments-everywhere.toml create mode 100644 toml-0.4.5/tests/valid/datetime-truncate.json create mode 100644 toml-0.4.5/tests/valid/datetime-truncate.toml create mode 100644 toml-0.4.5/tests/valid/datetime.json create mode 100644 toml-0.4.5/tests/valid/datetime.toml create mode 100644 toml-0.4.5/tests/valid/empty.json create mode 100644 toml-0.4.5/tests/valid/empty.toml create mode 100644 toml-0.4.5/tests/valid/example-bom.toml create mode 100644 toml-0.4.5/tests/valid/example-v0.3.0.json create mode 100644 toml-0.4.5/tests/valid/example-v0.3.0.toml create mode 100644 toml-0.4.5/tests/valid/example-v0.4.0.json create mode 100644 toml-0.4.5/tests/valid/example-v0.4.0.toml create mode 100644 toml-0.4.5/tests/valid/example.json create mode 100644 toml-0.4.5/tests/valid/example.toml create mode 100644 toml-0.4.5/tests/valid/example2.json create mode 100644 toml-0.4.5/tests/valid/example2.toml create mode 100644 toml-0.4.5/tests/valid/float.json create mode 100644 toml-0.4.5/tests/valid/float.toml create mode 100644 toml-0.4.5/tests/valid/hard_example.json create mode 100644 toml-0.4.5/tests/valid/hard_example.toml create mode 100644 toml-0.4.5/tests/valid/implicit-and-explicit-after.json create mode 100644 toml-0.4.5/tests/valid/implicit-and-explicit-after.toml create mode 100644 toml-0.4.5/tests/valid/implicit-and-explicit-before.json create mode 100644 toml-0.4.5/tests/valid/implicit-and-explicit-before.toml create mode 100644 toml-0.4.5/tests/valid/implicit-groups.json create mode 100644 toml-0.4.5/tests/valid/implicit-groups.toml create mode 100644 toml-0.4.5/tests/valid/integer.json create mode 100644 toml-0.4.5/tests/valid/integer.toml create mode 100644 toml-0.4.5/tests/valid/key-equals-nospace.json create mode 100644 toml-0.4.5/tests/valid/key-equals-nospace.toml create mode 100644 toml-0.4.5/tests/valid/key-quote-newline.json create mode 100644 toml-0.4.5/tests/valid/key-quote-newline.toml create mode 100644 toml-0.4.5/tests/valid/key-space.json create mode 100644 toml-0.4.5/tests/valid/key-space.toml create mode 100644 toml-0.4.5/tests/valid/key-special-chars.json create mode 100644 toml-0.4.5/tests/valid/key-special-chars.toml create mode 100644 toml-0.4.5/tests/valid/key-with-pound.json create mode 100644 toml-0.4.5/tests/valid/key-with-pound.toml create mode 100644 toml-0.4.5/tests/valid/long-float.json create mode 100644 toml-0.4.5/tests/valid/long-float.toml create mode 100644 toml-0.4.5/tests/valid/long-integer.json create mode 100644 toml-0.4.5/tests/valid/long-integer.toml create mode 100644 toml-0.4.5/tests/valid/multiline-string.json create mode 100644 toml-0.4.5/tests/valid/multiline-string.toml create mode 100644 toml-0.4.5/tests/valid/raw-multiline-string.json create mode 100644 toml-0.4.5/tests/valid/raw-multiline-string.toml create mode 100644 toml-0.4.5/tests/valid/raw-string.json create mode 100644 toml-0.4.5/tests/valid/raw-string.toml create mode 100644 toml-0.4.5/tests/valid/string-empty.json create mode 100644 toml-0.4.5/tests/valid/string-empty.toml create mode 100644 toml-0.4.5/tests/valid/string-escapes.json create mode 100644 toml-0.4.5/tests/valid/string-escapes.toml create mode 100644 toml-0.4.5/tests/valid/string-simple.json create mode 100644 toml-0.4.5/tests/valid/string-simple.toml create mode 100644 toml-0.4.5/tests/valid/string-with-pound.json create mode 100644 toml-0.4.5/tests/valid/string-with-pound.toml create mode 100644 toml-0.4.5/tests/valid/table-array-implicit.json create mode 100644 toml-0.4.5/tests/valid/table-array-implicit.toml create mode 100644 toml-0.4.5/tests/valid/table-array-many.json create mode 100644 toml-0.4.5/tests/valid/table-array-many.toml create mode 100644 toml-0.4.5/tests/valid/table-array-nest-no-keys.json create mode 100644 toml-0.4.5/tests/valid/table-array-nest-no-keys.toml create mode 100644 toml-0.4.5/tests/valid/table-array-nest.json create mode 100644 toml-0.4.5/tests/valid/table-array-nest.toml create mode 100644 toml-0.4.5/tests/valid/table-array-one.json create mode 100644 toml-0.4.5/tests/valid/table-array-one.toml create mode 100644 toml-0.4.5/tests/valid/table-empty.json create mode 100644 toml-0.4.5/tests/valid/table-empty.toml create mode 100644 toml-0.4.5/tests/valid/table-multi-empty.json create mode 100644 toml-0.4.5/tests/valid/table-multi-empty.toml create mode 100644 toml-0.4.5/tests/valid/table-sub-empty.json create mode 100644 toml-0.4.5/tests/valid/table-sub-empty.toml create mode 100644 toml-0.4.5/tests/valid/table-whitespace.json create mode 100644 toml-0.4.5/tests/valid/table-whitespace.toml create mode 100644 toml-0.4.5/tests/valid/table-with-pound.json create mode 100644 toml-0.4.5/tests/valid/table-with-pound.toml create mode 100644 toml-0.4.5/tests/valid/unicode-escape.json create mode 100644 toml-0.4.5/tests/valid/unicode-escape.toml create mode 100644 toml-0.4.5/tests/valid/unicode-literal.json create mode 100644 toml-0.4.5/tests/valid/unicode-literal.toml create mode 100644 unicode-bidi-0.3.4/.appveyor.yml create mode 100644 unicode-bidi-0.3.4/.cargo-checksum.json create mode 100644 unicode-bidi-0.3.4/.rustfmt.toml create mode 100644 unicode-bidi-0.3.4/.travis.yml create mode 100644 unicode-bidi-0.3.4/AUTHORS create mode 100644 unicode-bidi-0.3.4/COPYRIGHT create mode 100644 unicode-bidi-0.3.4/Cargo.toml create mode 100644 unicode-bidi-0.3.4/LICENSE-APACHE create mode 100644 unicode-bidi-0.3.4/LICENSE-MIT create mode 100644 unicode-bidi-0.3.4/README.md create mode 100644 unicode-bidi-0.3.4/src/char_data/mod.rs create mode 100644 unicode-bidi-0.3.4/src/char_data/tables.rs create mode 100644 unicode-bidi-0.3.4/src/deprecated.rs create mode 100644 unicode-bidi-0.3.4/src/explicit.rs create mode 100644 unicode-bidi-0.3.4/src/format_chars.rs create mode 100644 unicode-bidi-0.3.4/src/implicit.rs create mode 100644 unicode-bidi-0.3.4/src/level.rs create mode 100644 unicode-bidi-0.3.4/src/lib.rs create mode 100644 unicode-bidi-0.3.4/src/prepare.rs create mode 100644 unicode-normalization-0.1.5/.cargo-checksum.json create mode 100644 unicode-normalization-0.1.5/.travis.yml create mode 100644 unicode-normalization-0.1.5/COPYRIGHT create mode 100644 unicode-normalization-0.1.5/Cargo.toml create mode 100644 unicode-normalization-0.1.5/LICENSE-APACHE create mode 100644 unicode-normalization-0.1.5/LICENSE-MIT create mode 100644 unicode-normalization-0.1.5/README.md create mode 100755 unicode-normalization-0.1.5/scripts/unicode.py create mode 100755 unicode-normalization-0.1.5/scripts/unicode_gen_normtests.py create mode 100644 unicode-normalization-0.1.5/src/decompose.rs create mode 100644 unicode-normalization-0.1.5/src/lib.rs create mode 100644 unicode-normalization-0.1.5/src/normalize.rs create mode 100644 unicode-normalization-0.1.5/src/recompose.rs create mode 100644 unicode-normalization-0.1.5/src/tables.rs create mode 100644 unicode-normalization-0.1.5/src/test.rs create mode 100644 unicode-normalization-0.1.5/src/testdata.rs create mode 100644 unicode-xid-0.0.4/.cargo-checksum.json create mode 100644 unicode-xid-0.0.4/.travis.yml create mode 100644 unicode-xid-0.0.4/COPYRIGHT create mode 100644 unicode-xid-0.0.4/Cargo.toml create mode 100644 unicode-xid-0.0.4/LICENSE-APACHE create mode 100644 unicode-xid-0.0.4/LICENSE-MIT create mode 100644 unicode-xid-0.0.4/README.md create mode 100755 unicode-xid-0.0.4/scripts/unicode.py create mode 100644 unicode-xid-0.0.4/src/lib.rs create mode 100644 unicode-xid-0.0.4/src/tables.rs create mode 100644 unicode-xid-0.0.4/src/tests.rs create mode 100644 unreachable-1.0.0/.cargo-checksum.json create mode 100644 unreachable-1.0.0/.travis.yml create mode 100644 unreachable-1.0.0/Cargo.toml create mode 100644 unreachable-1.0.0/LICENSE-APACHE create mode 100644 unreachable-1.0.0/LICENSE-MIT create mode 100644 unreachable-1.0.0/README.md create mode 100644 unreachable-1.0.0/src/lib.rs create mode 100644 url-1.6.0/.cargo-checksum.json create mode 100644 url-1.6.0/.travis.yml create mode 100644 url-1.6.0/Cargo.toml create mode 100644 url-1.6.0/LICENSE-APACHE create mode 100644 url-1.6.0/LICENSE-MIT create mode 100644 url-1.6.0/Makefile create mode 100644 url-1.6.0/README.md create mode 100644 url-1.6.0/UPGRADING.md create mode 100644 url-1.6.0/appveyor.yml create mode 100644 url-1.6.0/docs/.nojekyll create mode 100644 url-1.6.0/docs/404.html create mode 100644 url-1.6.0/docs/index.html create mode 100644 url-1.6.0/github.png create mode 100644 url-1.6.0/rust-url-todo create mode 100644 url-1.6.0/src/encoding.rs create mode 100644 url-1.6.0/src/form_urlencoded.rs create mode 100644 url-1.6.0/src/host.rs create mode 100644 url-1.6.0/src/lib.rs create mode 100644 url-1.6.0/src/origin.rs create mode 100644 url-1.6.0/src/parser.rs create mode 100644 url-1.6.0/src/path_segments.rs create mode 100644 url-1.6.0/src/quirks.rs create mode 100644 url-1.6.0/src/slicing.rs create mode 100644 url-1.6.0/tests/data.rs create mode 100644 url-1.6.0/tests/setters_tests.json create mode 100644 url-1.6.0/tests/unit.rs create mode 100644 url-1.6.0/tests/urltestdata.json create mode 100644 userenv-sys-0.2.0/.cargo-checksum.json create mode 100644 userenv-sys-0.2.0/Cargo.toml create mode 100644 userenv-sys-0.2.0/README.md create mode 100644 userenv-sys-0.2.0/build.rs create mode 100644 userenv-sys-0.2.0/src/lib.rs create mode 100644 utf8-ranges-0.1.3/.cargo-checksum.json create mode 100644 utf8-ranges-0.1.3/.travis.yml create mode 100644 utf8-ranges-0.1.3/COPYING create mode 100644 utf8-ranges-0.1.3/Cargo.toml create mode 100644 utf8-ranges-0.1.3/LICENSE-MIT create mode 100644 utf8-ranges-0.1.3/Makefile create mode 100644 utf8-ranges-0.1.3/README.md create mode 100644 utf8-ranges-0.1.3/UNLICENSE create mode 100644 utf8-ranges-0.1.3/benches/bench.rs create mode 100644 utf8-ranges-0.1.3/ctags.rust create mode 100644 utf8-ranges-0.1.3/session.vim create mode 100644 utf8-ranges-0.1.3/src/char_utf8.rs create mode 100644 utf8-ranges-0.1.3/src/lib.rs create mode 100644 utf8-ranges-1.0.0/.cargo-checksum.json create mode 100644 utf8-ranges-1.0.0/.travis.yml create mode 100644 utf8-ranges-1.0.0/COPYING create mode 100644 utf8-ranges-1.0.0/Cargo.toml create mode 100644 utf8-ranges-1.0.0/LICENSE-MIT create mode 100644 utf8-ranges-1.0.0/Makefile create mode 100644 utf8-ranges-1.0.0/README.md create mode 100644 utf8-ranges-1.0.0/UNLICENSE create mode 100644 utf8-ranges-1.0.0/benches/bench.rs create mode 100644 utf8-ranges-1.0.0/ctags.rust create mode 100644 utf8-ranges-1.0.0/session.vim create mode 100644 utf8-ranges-1.0.0/src/char_utf8.rs create mode 100644 utf8-ranges-1.0.0/src/lib.rs create mode 100644 vcpkg-0.2.2/.cargo-checksum.json create mode 100644 vcpkg-0.2.2/Cargo.toml create mode 100644 vcpkg-0.2.2/src/lib.rs create mode 100644 void-1.0.2/.cargo-checksum.json create mode 100644 void-1.0.2/.travis.yml create mode 100644 void-1.0.2/Cargo.toml create mode 100644 void-1.0.2/README.md create mode 100644 void-1.0.2/src/lib.rs create mode 100644 walkdir-1.0.7/.cargo-checksum.json create mode 100644 walkdir-1.0.7/.travis.yml create mode 100644 walkdir-1.0.7/COPYING create mode 100644 walkdir-1.0.7/Cargo.toml create mode 100644 walkdir-1.0.7/LICENSE-MIT create mode 100644 walkdir-1.0.7/Makefile create mode 100644 walkdir-1.0.7/README.md create mode 100644 walkdir-1.0.7/UNLICENSE create mode 100644 walkdir-1.0.7/appveyor.yml create mode 100644 walkdir-1.0.7/compare/nftw.c create mode 100644 walkdir-1.0.7/compare/walk.py create mode 100644 walkdir-1.0.7/ctags.rust create mode 100644 walkdir-1.0.7/examples/walkdir.rs create mode 100644 walkdir-1.0.7/session.vim create mode 100644 walkdir-1.0.7/src/lib.rs create mode 100644 walkdir-1.0.7/src/tests.rs create mode 100644 winapi-0.2.8/.cargo-checksum.json create mode 100644 winapi-0.2.8/Cargo.toml create mode 100644 winapi-0.2.8/LICENSE.md create mode 100644 winapi-0.2.8/src/activation.rs create mode 100644 winapi-0.2.8/src/audioclient.rs create mode 100644 winapi-0.2.8/src/audiosessiontypes.rs create mode 100644 winapi-0.2.8/src/basetsd.rs create mode 100644 winapi-0.2.8/src/bcrypt.rs create mode 100644 winapi-0.2.8/src/cfg.rs create mode 100644 winapi-0.2.8/src/cfgmgr32.rs create mode 100644 winapi-0.2.8/src/combaseapi.rs create mode 100644 winapi-0.2.8/src/commctrl.rs create mode 100644 winapi-0.2.8/src/commdlg.rs create mode 100644 winapi-0.2.8/src/corsym.rs create mode 100644 winapi-0.2.8/src/d2d1.rs create mode 100644 winapi-0.2.8/src/d2dbasetypes.rs create mode 100644 winapi-0.2.8/src/d3d10shader.rs create mode 100644 winapi-0.2.8/src/d3d11.rs create mode 100644 winapi-0.2.8/src/d3d11shader.rs create mode 100644 winapi-0.2.8/src/d3d12.rs create mode 100644 winapi-0.2.8/src/d3d12sdklayers.rs create mode 100644 winapi-0.2.8/src/d3d12shader.rs create mode 100644 winapi-0.2.8/src/d3d9.rs create mode 100644 winapi-0.2.8/src/d3d9caps.rs create mode 100644 winapi-0.2.8/src/d3d9types.rs create mode 100644 winapi-0.2.8/src/d3dcommon.rs create mode 100644 winapi-0.2.8/src/d3dcompiler.rs create mode 100644 winapi-0.2.8/src/dbghelp.rs create mode 100644 winapi-0.2.8/src/dcommon.rs create mode 100644 winapi-0.2.8/src/devpropdef.rs create mode 100644 winapi-0.2.8/src/docobj.rs create mode 100644 winapi-0.2.8/src/dpapi.rs create mode 100644 winapi-0.2.8/src/dsgetdc.rs create mode 100644 winapi-0.2.8/src/dsound.rs create mode 100644 winapi-0.2.8/src/dsrole.rs create mode 100644 winapi-0.2.8/src/dwmapi.rs create mode 100644 winapi-0.2.8/src/dwrite.rs create mode 100644 winapi-0.2.8/src/dxgi.rs create mode 100644 winapi-0.2.8/src/dxgi1_2.rs create mode 100644 winapi-0.2.8/src/dxgi1_3.rs create mode 100644 winapi-0.2.8/src/dxgi1_4.rs create mode 100644 winapi-0.2.8/src/dxgiformat.rs create mode 100644 winapi-0.2.8/src/dxgitype.rs create mode 100644 winapi-0.2.8/src/errhandlingapi.rs create mode 100644 winapi-0.2.8/src/excpt.rs create mode 100644 winapi-0.2.8/src/fileapi.rs create mode 100644 winapi-0.2.8/src/gl.rs create mode 100644 winapi-0.2.8/src/guiddef.rs create mode 100644 winapi-0.2.8/src/heapapi.rs create mode 100644 winapi-0.2.8/src/hidclass.rs create mode 100644 winapi-0.2.8/src/hidpi.rs create mode 100644 winapi-0.2.8/src/hidsdi.rs create mode 100644 winapi-0.2.8/src/hidusage.rs create mode 100644 winapi-0.2.8/src/hstring.rs create mode 100644 winapi-0.2.8/src/http.rs create mode 100644 winapi-0.2.8/src/imm.rs create mode 100644 winapi-0.2.8/src/inaddr.rs create mode 100644 winapi-0.2.8/src/inspectable.rs create mode 100644 winapi-0.2.8/src/ksmedia.rs create mode 100644 winapi-0.2.8/src/lib.rs create mode 100644 winapi-0.2.8/src/libloaderapi.rs create mode 100644 winapi-0.2.8/src/lmaccess.rs create mode 100644 winapi-0.2.8/src/lmcons.rs create mode 100644 winapi-0.2.8/src/lmdfs.rs create mode 100644 winapi-0.2.8/src/lmerrlog.rs create mode 100644 winapi-0.2.8/src/lmjoin.rs create mode 100644 winapi-0.2.8/src/lsalookup.rs create mode 100644 winapi-0.2.8/src/macros.rs create mode 100644 winapi-0.2.8/src/memoryapi.rs create mode 100644 winapi-0.2.8/src/minschannel.rs create mode 100644 winapi-0.2.8/src/minwinbase.rs create mode 100644 winapi-0.2.8/src/minwindef.rs create mode 100644 winapi-0.2.8/src/mmdeviceapi.rs create mode 100644 winapi-0.2.8/src/mmreg.rs create mode 100644 winapi-0.2.8/src/mmsystem.rs create mode 100644 winapi-0.2.8/src/mscat.rs create mode 100644 winapi-0.2.8/src/mssip.rs create mode 100644 winapi-0.2.8/src/nb30.rs create mode 100644 winapi-0.2.8/src/ncrypt.rs create mode 100644 winapi-0.2.8/src/ntdef.rs create mode 100644 winapi-0.2.8/src/ntsecapi.rs create mode 100644 winapi-0.2.8/src/ntstatus.rs create mode 100644 winapi-0.2.8/src/oaidl.rs create mode 100644 winapi-0.2.8/src/objbase.rs create mode 100644 winapi-0.2.8/src/objidl.rs create mode 100644 winapi-0.2.8/src/objidlbase.rs create mode 100644 winapi-0.2.8/src/olectl.rs create mode 100644 winapi-0.2.8/src/pdh.rs create mode 100644 winapi-0.2.8/src/playsoundapi.rs create mode 100644 winapi-0.2.8/src/processsnapshot.rs create mode 100644 winapi-0.2.8/src/processthreadsapi.rs create mode 100644 winapi-0.2.8/src/propidl.rs create mode 100644 winapi-0.2.8/src/propsys.rs create mode 100644 winapi-0.2.8/src/prsht.rs create mode 100644 winapi-0.2.8/src/psapi.rs create mode 100644 winapi-0.2.8/src/qos.rs create mode 100644 winapi-0.2.8/src/reason.rs create mode 100644 winapi-0.2.8/src/restrictederrorinfo.rs create mode 100644 winapi-0.2.8/src/roapi.rs create mode 100644 winapi-0.2.8/src/roerrorapi.rs create mode 100644 winapi-0.2.8/src/rpc.rs create mode 100644 winapi-0.2.8/src/rpcdce.rs create mode 100644 winapi-0.2.8/src/sapi.rs create mode 100644 winapi-0.2.8/src/schannel.rs create mode 100644 winapi-0.2.8/src/servprov.rs create mode 100644 winapi-0.2.8/src/setupapi.rs create mode 100644 winapi-0.2.8/src/shellapi.rs create mode 100644 winapi-0.2.8/src/shellscalingapi.rs create mode 100644 winapi-0.2.8/src/shlguid.rs create mode 100644 winapi-0.2.8/src/shlobj.rs create mode 100644 winapi-0.2.8/src/shobjidl.rs create mode 100644 winapi-0.2.8/src/shtypes.rs create mode 100644 winapi-0.2.8/src/spapidef.rs create mode 100644 winapi-0.2.8/src/sql.rs create mode 100644 winapi-0.2.8/src/sqltypes.rs create mode 100644 winapi-0.2.8/src/sspi.rs create mode 100644 winapi-0.2.8/src/strmif.rs create mode 100644 winapi-0.2.8/src/subauth.rs create mode 100644 winapi-0.2.8/src/synchapi.rs create mode 100644 winapi-0.2.8/src/sysinfoapi.rs create mode 100644 winapi-0.2.8/src/threadpoolapi.rs create mode 100644 winapi-0.2.8/src/timezoneapi.rs create mode 100644 winapi-0.2.8/src/tlhelp32.rs create mode 100644 winapi-0.2.8/src/unknwnbase.rs create mode 100644 winapi-0.2.8/src/urlhist.rs create mode 100644 winapi-0.2.8/src/urlmon.rs create mode 100644 winapi-0.2.8/src/usb.rs create mode 100644 winapi-0.2.8/src/usbspec.rs create mode 100644 winapi-0.2.8/src/usp10.rs create mode 100644 winapi-0.2.8/src/vadefs.rs create mode 100644 winapi-0.2.8/src/vsbackup.rs create mode 100644 winapi-0.2.8/src/vss.rs create mode 100644 winapi-0.2.8/src/vsserror.rs create mode 100644 winapi-0.2.8/src/vswriter.rs create mode 100644 winapi-0.2.8/src/werapi.rs create mode 100644 winapi-0.2.8/src/winbase.rs create mode 100644 winapi-0.2.8/src/wincon.rs create mode 100644 winapi-0.2.8/src/wincred.rs create mode 100644 winapi-0.2.8/src/wincrypt.rs create mode 100644 winapi-0.2.8/src/windef.rs create mode 100644 winapi-0.2.8/src/windowscodecs.rs create mode 100644 winapi-0.2.8/src/windowsx.rs create mode 100644 winapi-0.2.8/src/winerror.rs create mode 100644 winapi-0.2.8/src/winevt.rs create mode 100644 winapi-0.2.8/src/wingdi.rs create mode 100644 winapi-0.2.8/src/winhttp.rs create mode 100644 winapi-0.2.8/src/winioctl.rs create mode 100644 winapi-0.2.8/src/winnetwk.rs create mode 100644 winapi-0.2.8/src/winnls.rs create mode 100644 winapi-0.2.8/src/winnt.rs create mode 100644 winapi-0.2.8/src/winreg.rs create mode 100644 winapi-0.2.8/src/winscard.rs create mode 100644 winapi-0.2.8/src/winsmcrd.rs create mode 100644 winapi-0.2.8/src/winsock2.rs create mode 100644 winapi-0.2.8/src/winspool.rs create mode 100644 winapi-0.2.8/src/winstring.rs create mode 100644 winapi-0.2.8/src/winsvc.rs create mode 100644 winapi-0.2.8/src/winusb.rs create mode 100644 winapi-0.2.8/src/winusbio.rs create mode 100644 winapi-0.2.8/src/winuser.rs create mode 100644 winapi-0.2.8/src/ws2def.rs create mode 100644 winapi-0.2.8/src/ws2ipdef.rs create mode 100644 winapi-0.2.8/src/ws2spi.rs create mode 100644 winapi-0.2.8/src/ws2tcpip.rs create mode 100644 winapi-0.2.8/src/wtypes.rs create mode 100644 winapi-0.2.8/src/wtypesbase.rs create mode 100644 winapi-0.2.8/src/xinput.rs create mode 100644 winapi-0.3.3/.cargo-checksum.json create mode 100644 winapi-0.3.3/Cargo.toml create mode 100644 winapi-0.3.3/LICENSE-APACHE create mode 100644 winapi-0.3.3/LICENSE-MIT create mode 100644 winapi-0.3.3/README.md create mode 100644 winapi-0.3.3/build.rs create mode 100644 winapi-0.3.3/src/lib.rs create mode 100644 winapi-0.3.3/src/macros.rs create mode 100644 winapi-0.3.3/src/shared/basetsd.rs create mode 100644 winapi-0.3.3/src/shared/bcrypt.rs create mode 100644 winapi-0.3.3/src/shared/bugcodes.rs create mode 100644 winapi-0.3.3/src/shared/cderr.rs create mode 100644 winapi-0.3.3/src/shared/cfg.rs create mode 100644 winapi-0.3.3/src/shared/d3d9.rs create mode 100644 winapi-0.3.3/src/shared/d3d9caps.rs create mode 100644 winapi-0.3.3/src/shared/d3d9types.rs create mode 100644 winapi-0.3.3/src/shared/dcomptypes.rs create mode 100644 winapi-0.3.3/src/shared/devguid.rs create mode 100644 winapi-0.3.3/src/shared/devpkey.rs create mode 100644 winapi-0.3.3/src/shared/devpropdef.rs create mode 100644 winapi-0.3.3/src/shared/dinputd.rs create mode 100644 winapi-0.3.3/src/shared/dxgi.rs create mode 100644 winapi-0.3.3/src/shared/dxgi1_2.rs create mode 100644 winapi-0.3.3/src/shared/dxgi1_3.rs create mode 100644 winapi-0.3.3/src/shared/dxgi1_4.rs create mode 100644 winapi-0.3.3/src/shared/dxgi1_5.rs create mode 100644 winapi-0.3.3/src/shared/dxgiformat.rs create mode 100644 winapi-0.3.3/src/shared/dxgitype.rs create mode 100644 winapi-0.3.3/src/shared/guiddef.rs create mode 100644 winapi-0.3.3/src/shared/hidclass.rs create mode 100644 winapi-0.3.3/src/shared/hidpi.rs create mode 100644 winapi-0.3.3/src/shared/hidsdi.rs create mode 100644 winapi-0.3.3/src/shared/hidusage.rs create mode 100644 winapi-0.3.3/src/shared/in6addr.rs create mode 100644 winapi-0.3.3/src/shared/inaddr.rs create mode 100644 winapi-0.3.3/src/shared/intsafe.rs create mode 100644 winapi-0.3.3/src/shared/ksmedia.rs create mode 100644 winapi-0.3.3/src/shared/ktmtypes.rs create mode 100644 winapi-0.3.3/src/shared/lmcons.rs create mode 100644 winapi-0.3.3/src/shared/minwindef.rs create mode 100644 winapi-0.3.3/src/shared/mmreg.rs create mode 100644 winapi-0.3.3/src/shared/mod.rs create mode 100644 winapi-0.3.3/src/shared/mstcpip.rs create mode 100644 winapi-0.3.3/src/shared/ntddscsi.rs create mode 100644 winapi-0.3.3/src/shared/ntddser.rs create mode 100644 winapi-0.3.3/src/shared/ntdef.rs create mode 100644 winapi-0.3.3/src/shared/ntstatus.rs create mode 100644 winapi-0.3.3/src/shared/qos.rs create mode 100644 winapi-0.3.3/src/shared/rpc.rs create mode 100644 winapi-0.3.3/src/shared/rpcdce.rs create mode 100644 winapi-0.3.3/src/shared/rpcndr.rs create mode 100644 winapi-0.3.3/src/shared/sspi.rs create mode 100644 winapi-0.3.3/src/shared/stralign.rs create mode 100644 winapi-0.3.3/src/shared/usb.rs create mode 100644 winapi-0.3.3/src/shared/usbiodef.rs create mode 100644 winapi-0.3.3/src/shared/usbspec.rs create mode 100644 winapi-0.3.3/src/shared/windef.rs create mode 100644 winapi-0.3.3/src/shared/windowsx.rs create mode 100644 winapi-0.3.3/src/shared/winerror.rs create mode 100644 winapi-0.3.3/src/shared/winusbio.rs create mode 100644 winapi-0.3.3/src/shared/wnnc.rs create mode 100644 winapi-0.3.3/src/shared/ws2def.rs create mode 100644 winapi-0.3.3/src/shared/ws2ipdef.rs create mode 100644 winapi-0.3.3/src/shared/wtypes.rs create mode 100644 winapi-0.3.3/src/shared/wtypesbase.rs create mode 100644 winapi-0.3.3/src/um/audioclient.rs create mode 100644 winapi-0.3.3/src/um/audiosessiontypes.rs create mode 100644 winapi-0.3.3/src/um/avrt.rs create mode 100644 winapi-0.3.3/src/um/cfgmgr32.rs create mode 100644 winapi-0.3.3/src/um/cguid.rs create mode 100644 winapi-0.3.3/src/um/combaseapi.rs create mode 100644 winapi-0.3.3/src/um/coml2api.rs create mode 100644 winapi-0.3.3/src/um/commapi.rs create mode 100644 winapi-0.3.3/src/um/commctrl.rs create mode 100644 winapi-0.3.3/src/um/commdlg.rs create mode 100644 winapi-0.3.3/src/um/commoncontrols.rs create mode 100644 winapi-0.3.3/src/um/consoleapi.rs create mode 100644 winapi-0.3.3/src/um/corsym.rs create mode 100644 winapi-0.3.3/src/um/d2d1.rs create mode 100644 winapi-0.3.3/src/um/d2d1_1.rs create mode 100644 winapi-0.3.3/src/um/d2d1_2.rs create mode 100644 winapi-0.3.3/src/um/d2d1effectauthor.rs create mode 100644 winapi-0.3.3/src/um/d2d1effects.rs create mode 100644 winapi-0.3.3/src/um/d2d1effects_1.rs create mode 100644 winapi-0.3.3/src/um/d2d1effects_2.rs create mode 100644 winapi-0.3.3/src/um/d2dbasetypes.rs create mode 100644 winapi-0.3.3/src/um/d3d.rs create mode 100644 winapi-0.3.3/src/um/d3d10.rs create mode 100644 winapi-0.3.3/src/um/d3d10_1.rs create mode 100644 winapi-0.3.3/src/um/d3d10_1shader.rs create mode 100644 winapi-0.3.3/src/um/d3d10effect.rs create mode 100644 winapi-0.3.3/src/um/d3d10misc.rs create mode 100644 winapi-0.3.3/src/um/d3d10sdklayers.rs create mode 100644 winapi-0.3.3/src/um/d3d10shader.rs create mode 100644 winapi-0.3.3/src/um/d3d11.rs create mode 100644 winapi-0.3.3/src/um/d3d11_1.rs create mode 100644 winapi-0.3.3/src/um/d3d11_2.rs create mode 100644 winapi-0.3.3/src/um/d3d11_3.rs create mode 100644 winapi-0.3.3/src/um/d3d11_4.rs create mode 100644 winapi-0.3.3/src/um/d3d11on12.rs create mode 100644 winapi-0.3.3/src/um/d3d11sdklayers.rs create mode 100644 winapi-0.3.3/src/um/d3d11shader.rs create mode 100644 winapi-0.3.3/src/um/d3d12.rs create mode 100644 winapi-0.3.3/src/um/d3d12sdklayers.rs create mode 100644 winapi-0.3.3/src/um/d3d12shader.rs create mode 100644 winapi-0.3.3/src/um/d3dcommon.rs create mode 100644 winapi-0.3.3/src/um/d3dcompiler.rs create mode 100644 winapi-0.3.3/src/um/d3dcsx.rs create mode 100644 winapi-0.3.3/src/um/d3dx10core.rs create mode 100644 winapi-0.3.3/src/um/d3dx10math.rs create mode 100644 winapi-0.3.3/src/um/d3dx10mesh.rs create mode 100644 winapi-0.3.3/src/um/datetimeapi.rs create mode 100644 winapi-0.3.3/src/um/davclnt.rs create mode 100644 winapi-0.3.3/src/um/dbghelp.rs create mode 100644 winapi-0.3.3/src/um/dcommon.rs create mode 100644 winapi-0.3.3/src/um/dcomp.rs create mode 100644 winapi-0.3.3/src/um/dcompanimation.rs create mode 100644 winapi-0.3.3/src/um/dde.rs create mode 100644 winapi-0.3.3/src/um/ddraw.rs create mode 100644 winapi-0.3.3/src/um/ddrawi.rs create mode 100644 winapi-0.3.3/src/um/ddrawint.rs create mode 100644 winapi-0.3.3/src/um/debugapi.rs create mode 100644 winapi-0.3.3/src/um/dinput.rs create mode 100644 winapi-0.3.3/src/um/dmksctl.rs create mode 100644 winapi-0.3.3/src/um/dmusicc.rs create mode 100644 winapi-0.3.3/src/um/docobj.rs create mode 100644 winapi-0.3.3/src/um/documenttarget.rs create mode 100644 winapi-0.3.3/src/um/dpa_dsa.rs create mode 100644 winapi-0.3.3/src/um/dpapi.rs create mode 100644 winapi-0.3.3/src/um/dsgetdc.rs create mode 100644 winapi-0.3.3/src/um/dsound.rs create mode 100644 winapi-0.3.3/src/um/dsrole.rs create mode 100644 winapi-0.3.3/src/um/dvp.rs create mode 100644 winapi-0.3.3/src/um/dwmapi.rs create mode 100644 winapi-0.3.3/src/um/dwrite.rs create mode 100644 winapi-0.3.3/src/um/dwrite_1.rs create mode 100644 winapi-0.3.3/src/um/dwrite_2.rs create mode 100644 winapi-0.3.3/src/um/dwrite_3.rs create mode 100644 winapi-0.3.3/src/um/dxdiag.rs create mode 100644 winapi-0.3.3/src/um/dxfile.rs create mode 100644 winapi-0.3.3/src/um/dxgidebug.rs create mode 100644 winapi-0.3.3/src/um/errhandlingapi.rs create mode 100644 winapi-0.3.3/src/um/fibersapi.rs create mode 100644 winapi-0.3.3/src/um/fileapi.rs create mode 100644 winapi-0.3.3/src/um/gl/gl.rs create mode 100644 winapi-0.3.3/src/um/gl/mod.rs create mode 100644 winapi-0.3.3/src/um/handleapi.rs create mode 100644 winapi-0.3.3/src/um/heapapi.rs create mode 100644 winapi-0.3.3/src/um/http.rs create mode 100644 winapi-0.3.3/src/um/imm.rs create mode 100644 winapi-0.3.3/src/um/interlockedapi.rs create mode 100644 winapi-0.3.3/src/um/ioapiset.rs create mode 100644 winapi-0.3.3/src/um/jobapi.rs create mode 100644 winapi-0.3.3/src/um/jobapi2.rs create mode 100644 winapi-0.3.3/src/um/knownfolders.rs create mode 100644 winapi-0.3.3/src/um/ktmw32.rs create mode 100644 winapi-0.3.3/src/um/libloaderapi.rs create mode 100644 winapi-0.3.3/src/um/lmaccess.rs create mode 100644 winapi-0.3.3/src/um/lmalert.rs create mode 100644 winapi-0.3.3/src/um/lmapibuf.rs create mode 100644 winapi-0.3.3/src/um/lmat.rs create mode 100644 winapi-0.3.3/src/um/lmdfs.rs create mode 100644 winapi-0.3.3/src/um/lmerrlog.rs create mode 100644 winapi-0.3.3/src/um/lmjoin.rs create mode 100644 winapi-0.3.3/src/um/lmmsg.rs create mode 100644 winapi-0.3.3/src/um/lmremutl.rs create mode 100644 winapi-0.3.3/src/um/lmrepl.rs create mode 100644 winapi-0.3.3/src/um/lmserver.rs create mode 100644 winapi-0.3.3/src/um/lmshare.rs create mode 100644 winapi-0.3.3/src/um/lmstats.rs create mode 100644 winapi-0.3.3/src/um/lmsvc.rs create mode 100644 winapi-0.3.3/src/um/lmuse.rs create mode 100644 winapi-0.3.3/src/um/lmwksta.rs create mode 100644 winapi-0.3.3/src/um/lsalookup.rs create mode 100644 winapi-0.3.3/src/um/memoryapi.rs create mode 100644 winapi-0.3.3/src/um/minschannel.rs create mode 100644 winapi-0.3.3/src/um/minwinbase.rs create mode 100644 winapi-0.3.3/src/um/mmdeviceapi.rs create mode 100644 winapi-0.3.3/src/um/mmeapi.rs create mode 100644 winapi-0.3.3/src/um/mmsystem.rs create mode 100644 winapi-0.3.3/src/um/mod.rs create mode 100644 winapi-0.3.3/src/um/msaatext.rs create mode 100644 winapi-0.3.3/src/um/mscat.rs create mode 100644 winapi-0.3.3/src/um/mssip.rs create mode 100644 winapi-0.3.3/src/um/namedpipeapi.rs create mode 100644 winapi-0.3.3/src/um/namespaceapi.rs create mode 100644 winapi-0.3.3/src/um/nb30.rs create mode 100644 winapi-0.3.3/src/um/ncrypt.rs create mode 100644 winapi-0.3.3/src/um/ntsecapi.rs create mode 100644 winapi-0.3.3/src/um/oaidl.rs create mode 100644 winapi-0.3.3/src/um/objbase.rs create mode 100644 winapi-0.3.3/src/um/objidl.rs create mode 100644 winapi-0.3.3/src/um/objidlbase.rs create mode 100644 winapi-0.3.3/src/um/ocidl.rs create mode 100644 winapi-0.3.3/src/um/oleauto.rs create mode 100644 winapi-0.3.3/src/um/olectl.rs create mode 100644 winapi-0.3.3/src/um/pdh.rs create mode 100644 winapi-0.3.3/src/um/playsoundapi.rs create mode 100644 winapi-0.3.3/src/um/powerbase.rs create mode 100644 winapi-0.3.3/src/um/powersetting.rs create mode 100644 winapi-0.3.3/src/um/powrprof.rs create mode 100644 winapi-0.3.3/src/um/processenv.rs create mode 100644 winapi-0.3.3/src/um/processsnapshot.rs create mode 100644 winapi-0.3.3/src/um/processthreadsapi.rs create mode 100644 winapi-0.3.3/src/um/processtopologyapi.rs create mode 100644 winapi-0.3.3/src/um/profileapi.rs create mode 100644 winapi-0.3.3/src/um/propidl.rs create mode 100644 winapi-0.3.3/src/um/propkeydef.rs create mode 100644 winapi-0.3.3/src/um/propsys.rs create mode 100644 winapi-0.3.3/src/um/prsht.rs create mode 100644 winapi-0.3.3/src/um/psapi.rs create mode 100644 winapi-0.3.3/src/um/realtimeapiset.rs create mode 100644 winapi-0.3.3/src/um/reason.rs create mode 100644 winapi-0.3.3/src/um/restrictederrorinfo.rs create mode 100644 winapi-0.3.3/src/um/rmxfguid.rs create mode 100644 winapi-0.3.3/src/um/sapi.rs create mode 100644 winapi-0.3.3/src/um/sapi51.rs create mode 100644 winapi-0.3.3/src/um/sapi53.rs create mode 100644 winapi-0.3.3/src/um/sapiddk.rs create mode 100644 winapi-0.3.3/src/um/sapiddk51.rs create mode 100644 winapi-0.3.3/src/um/schannel.rs create mode 100644 winapi-0.3.3/src/um/securityappcontainer.rs create mode 100644 winapi-0.3.3/src/um/securitybaseapi.rs create mode 100644 winapi-0.3.3/src/um/servprov.rs create mode 100644 winapi-0.3.3/src/um/setupapi.rs create mode 100644 winapi-0.3.3/src/um/shellapi.rs create mode 100644 winapi-0.3.3/src/um/shellscalingapi.rs create mode 100644 winapi-0.3.3/src/um/shlobj.rs create mode 100644 winapi-0.3.3/src/um/shobjidl.rs create mode 100644 winapi-0.3.3/src/um/shobjidl_core.rs create mode 100644 winapi-0.3.3/src/um/shtypes.rs create mode 100644 winapi-0.3.3/src/um/spapidef.rs create mode 100644 winapi-0.3.3/src/um/sporder.rs create mode 100644 winapi-0.3.3/src/um/sql.rs create mode 100644 winapi-0.3.3/src/um/sqlext.rs create mode 100644 winapi-0.3.3/src/um/sqltypes.rs create mode 100644 winapi-0.3.3/src/um/sqlucode.rs create mode 100644 winapi-0.3.3/src/um/sspi.rs create mode 100644 winapi-0.3.3/src/um/stringapiset.rs create mode 100644 winapi-0.3.3/src/um/strmif.rs create mode 100644 winapi-0.3.3/src/um/subauth.rs create mode 100644 winapi-0.3.3/src/um/synchapi.rs create mode 100644 winapi-0.3.3/src/um/sysinfoapi.rs create mode 100644 winapi-0.3.3/src/um/systemtopologyapi.rs create mode 100644 winapi-0.3.3/src/um/textstor.rs create mode 100644 winapi-0.3.3/src/um/threadpoolapiset.rs create mode 100644 winapi-0.3.3/src/um/threadpoollegacyapiset.rs create mode 100644 winapi-0.3.3/src/um/timeapi.rs create mode 100644 winapi-0.3.3/src/um/timezoneapi.rs create mode 100644 winapi-0.3.3/src/um/tlhelp32.rs create mode 100644 winapi-0.3.3/src/um/unknwnbase.rs create mode 100644 winapi-0.3.3/src/um/urlhist.rs create mode 100644 winapi-0.3.3/src/um/urlmon.rs create mode 100644 winapi-0.3.3/src/um/userenv.rs create mode 100644 winapi-0.3.3/src/um/usp10.rs create mode 100644 winapi-0.3.3/src/um/utilapiset.rs create mode 100644 winapi-0.3.3/src/um/vsbackup.rs create mode 100644 winapi-0.3.3/src/um/vss.rs create mode 100644 winapi-0.3.3/src/um/vsserror.rs create mode 100644 winapi-0.3.3/src/um/vswriter.rs create mode 100644 winapi-0.3.3/src/um/werapi.rs create mode 100644 winapi-0.3.3/src/um/winbase.rs create mode 100644 winapi-0.3.3/src/um/wincodec.rs create mode 100644 winapi-0.3.3/src/um/wincodecsdk.rs create mode 100644 winapi-0.3.3/src/um/wincon.rs create mode 100644 winapi-0.3.3/src/um/wincred.rs create mode 100644 winapi-0.3.3/src/um/wincrypt.rs create mode 100644 winapi-0.3.3/src/um/windowsceip.rs create mode 100644 winapi-0.3.3/src/um/winevt.rs create mode 100644 winapi-0.3.3/src/um/wingdi.rs create mode 100644 winapi-0.3.3/src/um/winhttp.rs create mode 100644 winapi-0.3.3/src/um/wininet.rs create mode 100644 winapi-0.3.3/src/um/winineti.rs create mode 100644 winapi-0.3.3/src/um/winioctl.rs create mode 100644 winapi-0.3.3/src/um/winnetwk.rs create mode 100644 winapi-0.3.3/src/um/winnls.rs create mode 100644 winapi-0.3.3/src/um/winnt.rs create mode 100644 winapi-0.3.3/src/um/winreg.rs create mode 100644 winapi-0.3.3/src/um/winscard.rs create mode 100644 winapi-0.3.3/src/um/winsmcrd.rs create mode 100644 winapi-0.3.3/src/um/winsock2.rs create mode 100644 winapi-0.3.3/src/um/winspool.rs create mode 100644 winapi-0.3.3/src/um/winsvc.rs create mode 100644 winapi-0.3.3/src/um/winusb.rs create mode 100644 winapi-0.3.3/src/um/winuser.rs create mode 100644 winapi-0.3.3/src/um/winver.rs create mode 100644 winapi-0.3.3/src/um/wow64apiset.rs create mode 100644 winapi-0.3.3/src/um/ws2spi.rs create mode 100644 winapi-0.3.3/src/um/ws2tcpip.rs create mode 100644 winapi-0.3.3/src/um/xinput.rs create mode 100644 winapi-0.3.3/src/vc/excpt.rs create mode 100644 winapi-0.3.3/src/vc/limits.rs create mode 100644 winapi-0.3.3/src/vc/mod.rs create mode 100644 winapi-0.3.3/src/vc/vadefs.rs create mode 100644 winapi-0.3.3/src/vc/vcruntime.rs create mode 100644 winapi-0.3.3/src/winrt/activation.rs create mode 100644 winapi-0.3.3/src/winrt/hstring.rs create mode 100644 winapi-0.3.3/src/winrt/inspectable.rs create mode 100644 winapi-0.3.3/src/winrt/mod.rs create mode 100644 winapi-0.3.3/src/winrt/roapi.rs create mode 100644 winapi-0.3.3/src/winrt/robuffer.rs create mode 100644 winapi-0.3.3/src/winrt/roerrorapi.rs create mode 100644 winapi-0.3.3/src/winrt/winstring.rs create mode 100644 winapi-build-0.1.1/.cargo-checksum.json create mode 100644 winapi-build-0.1.1/Cargo.toml create mode 100644 winapi-build-0.1.1/src/lib.rs create mode 100644 winapi-i686-pc-windows-gnu-0.3.2/.cargo-checksum.json create mode 100644 winapi-i686-pc-windows-gnu-0.3.2/Cargo.toml create mode 100644 winapi-i686-pc-windows-gnu-0.3.2/build.rs create mode 100644 winapi-i686-pc-windows-gnu-0.3.2/src/lib.rs create mode 100644 winapi-x86_64-pc-windows-gnu-0.3.2/.cargo-checksum.json create mode 100644 winapi-x86_64-pc-windows-gnu-0.3.2/Cargo.toml create mode 100644 winapi-x86_64-pc-windows-gnu-0.3.2/build.rs create mode 100644 winapi-x86_64-pc-windows-gnu-0.3.2/src/lib.rs create mode 100644 wincolor-0.1.4/.cargo-checksum.json create mode 100644 wincolor-0.1.4/COPYING create mode 100644 wincolor-0.1.4/Cargo.toml create mode 100644 wincolor-0.1.4/LICENSE-MIT create mode 100644 wincolor-0.1.4/README.md create mode 100644 wincolor-0.1.4/UNLICENSE create mode 100644 wincolor-0.1.4/src/lib.rs create mode 100644 wincolor-0.1.4/src/win.rs diff --git a/advapi32-sys-0.2.0/.cargo-checksum.json b/advapi32-sys-0.2.0/.cargo-checksum.json new file mode 100644 index 000000000..22bddd467 --- /dev/null +++ b/advapi32-sys-0.2.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a"} \ No newline at end of file diff --git a/advapi32-sys-0.2.0/Cargo.toml b/advapi32-sys-0.2.0/Cargo.toml new file mode 100644 index 000000000..fccf0ad80 --- /dev/null +++ b/advapi32-sys-0.2.0/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "advapi32-sys" +version = "0.2.0" +authors = ["Peter Atashian "] +description = "Contains function definitions for the Windows API library advapi32. See winapi for types and constants." +documentation = "https://retep998.github.io/doc/advapi32/" +repository = "https://github.com/retep998/winapi-rs" +readme = "README.md" +keywords = ["windows", "ffi", "win32"] +license = "MIT" +build = "build.rs" +[lib] +name = "advapi32" +[dependencies] +winapi = { version = "0.2.5", path = "../.." } +[build-dependencies] +winapi-build = { version = "0.1.1", path = "../../build" } diff --git a/advapi32-sys-0.2.0/README.md b/advapi32-sys-0.2.0/README.md new file mode 100644 index 000000000..c3d84c328 --- /dev/null +++ b/advapi32-sys-0.2.0/README.md @@ -0,0 +1,13 @@ +# advapi32 # +Contains function definitions for the Windows API library advapi32. See winapi for types and constants. + +```toml +[dependencies] +advapi32-sys = "0.1.2" +``` + +```rust +extern crate advapi32; +``` + +[Documentation](https://retep998.github.io/doc/advapi32/) diff --git a/advapi32-sys-0.2.0/build.rs b/advapi32-sys-0.2.0/build.rs new file mode 100644 index 000000000..639d0b305 --- /dev/null +++ b/advapi32-sys-0.2.0/build.rs @@ -0,0 +1,6 @@ +// Copyright © 2015, Peter Atashian +// Licensed under the MIT License +extern crate build; +fn main() { + build::link("advapi32", false) +} diff --git a/advapi32-sys-0.2.0/src/lib.rs b/advapi32-sys-0.2.0/src/lib.rs new file mode 100644 index 000000000..3c4a5221b --- /dev/null +++ b/advapi32-sys-0.2.0/src/lib.rs @@ -0,0 +1,1005 @@ +// Copyright © 2015, Peter Atashian +// Licensed under the MIT License +//! FFI bindings to advapi32. +#![cfg(windows)] +extern crate winapi; +use winapi::*; +extern "system" { + pub fn AbortSystemShutdownA(lpMachineName: LPCSTR) -> BOOL; + pub fn AbortSystemShutdownW(lpMachineName: LPWSTR) -> BOOL; + // pub fn AccessCheck(); + // pub fn AccessCheckAndAuditAlarmA(); + // pub fn AccessCheckAndAuditAlarmW(); + // pub fn AccessCheckByType(); + // pub fn AccessCheckByTypeAndAuditAlarmA(); + // pub fn AccessCheckByTypeAndAuditAlarmW(); + // pub fn AccessCheckByTypeResultList(); + // pub fn AccessCheckByTypeResultListAndAuditAlarmA(); + // pub fn AccessCheckByTypeResultListAndAuditAlarmByHandleA(); + // pub fn AccessCheckByTypeResultListAndAuditAlarmByHandleW(); + // pub fn AccessCheckByTypeResultListAndAuditAlarmW(); + // pub fn AddAccessAllowedAce(); + // pub fn AddAccessAllowedAceEx(); + // pub fn AddAccessAllowedObjectAce(); + // pub fn AddAccessDeniedAce(); + // pub fn AddAccessDeniedAceEx(); + // pub fn AddAccessDeniedObjectAce(); + // pub fn AddAce(); + // pub fn AddAuditAccessAce(); + // pub fn AddAuditAccessAceEx(); + // pub fn AddAuditAccessObjectAce(); + // pub fn AddConditionalAce(); + // pub fn AddMandatoryAce(); + // pub fn AddUsersToEncryptedFile(); + // pub fn AddUsersToEncryptedFileEx(); + // pub fn AdjustTokenGroups(); + pub fn AdjustTokenPrivileges( + TokenHandle: HANDLE, DisableAllPrivileges: BOOL, NewState: PTOKEN_PRIVILEGES, + BufferLength: DWORD, PreviousState: PTOKEN_PRIVILEGES, ReturnLength: PDWORD, + ) -> BOOL; + // pub fn AllocateAndInitializeSid(); + pub fn AllocateLocallyUniqueId(Luid: PLUID) -> BOOL; + pub fn AreAllAccessesGranted(GrantedAccess: DWORD, DesiredAccess: DWORD) -> BOOL; + pub fn AreAnyAccessesGranted(GrantedAccess: DWORD, DesiredAccess: DWORD) -> BOOL; + // pub fn AuditComputeEffectivePolicyBySid(); + // pub fn AuditComputeEffectivePolicyByToken(); + // pub fn AuditEnumerateCategories(); + // pub fn AuditEnumeratePerUserPolicy(); + // pub fn AuditEnumerateSubCategories(); + pub fn AuditFree(Buffer: PVOID); + // pub fn AuditLookupCategoryGuidFromCategoryId(); + // pub fn AuditLookupCategoryIdFromCategoryGuid(); + // pub fn AuditLookupCategoryNameA(); + // pub fn AuditLookupCategoryNameW(); + // pub fn AuditLookupSubCategoryNameA(); + // pub fn AuditLookupSubCategoryNameW(); + // pub fn AuditQueryGlobalSaclA(); + // pub fn AuditQueryGlobalSaclW(); + // pub fn AuditQueryPerUserPolicy(); + // pub fn AuditQuerySecurity(); + // pub fn AuditQuerySystemPolicy(); + // pub fn AuditSetGlobalSaclA(); + // pub fn AuditSetGlobalSaclW(); + // pub fn AuditSetPerUserPolicy(); + // pub fn AuditSetSecurity(); + // pub fn AuditSetSystemPolicy(); + // pub fn BackupEventLogA(); + // pub fn BackupEventLogW(); + // pub fn BaseRegCloseKey(); + // pub fn BaseRegCreateKey(); + // pub fn BaseRegDeleteKeyEx(); + // pub fn BaseRegDeleteValue(); + // pub fn BaseRegFlushKey(); + // pub fn BaseRegGetVersion(); + // pub fn BaseRegLoadKey(); + // pub fn BaseRegOpenKey(); + // pub fn BaseRegRestoreKey(); + // pub fn BaseRegSaveKeyEx(); + // pub fn BaseRegSetKeySecurity(); + // pub fn BaseRegSetValue(); + // pub fn BaseRegUnLoadKey(); + // pub fn BuildExplicitAccessWithNameA(); + // pub fn BuildExplicitAccessWithNameW(); + // pub fn BuildImpersonateExplicitAccessWithNameA(); + // pub fn BuildImpersonateExplicitAccessWithNameW(); + // pub fn BuildImpersonateTrusteeA(); + // pub fn BuildImpersonateTrusteeW(); + // pub fn BuildSecurityDescriptorA(); + // pub fn BuildSecurityDescriptorW(); + // pub fn BuildTrusteeWithNameA(); + // pub fn BuildTrusteeWithNameW(); + // pub fn BuildTrusteeWithObjectsAndNameA(); + // pub fn BuildTrusteeWithObjectsAndNameW(); + // pub fn BuildTrusteeWithObjectsAndSidA(); + // pub fn BuildTrusteeWithObjectsAndSidW(); + // pub fn BuildTrusteeWithSidA(); + // pub fn BuildTrusteeWithSidW(); + // pub fn CancelOverlappedAccess(); + // pub fn ChangeServiceConfig2A(); + // pub fn ChangeServiceConfig2W(); + // pub fn ChangeServiceConfigA(); + // pub fn ChangeServiceConfigW(); + // pub fn CheckForHiberboot(); + // pub fn CheckTokenMembership(); + // pub fn ClearEventLogA(); + // pub fn ClearEventLogW(); + // pub fn CloseCodeAuthzLevel(); + // pub fn CloseEncryptedFileRaw(); + // pub fn CloseEventLog(); + pub fn CloseServiceHandle(hSCObject: SC_HANDLE) -> BOOL; + // pub fn CloseThreadWaitChainSession(); + // pub fn CloseTrace(); + // pub fn CommandLineFromMsiDescriptor(); + // pub fn ComputeAccessTokenFromCodeAuthzLevel(); + pub fn ControlService( + hService: SC_HANDLE, dwControl: DWORD, lpServiceStatus: LPSERVICE_STATUS, + ) -> BOOL; + // pub fn ControlServiceExA(); + // pub fn ControlServiceExW(); + // pub fn ControlTraceA(); + // pub fn ControlTraceW(); + // pub fn ConvertAccessToSecurityDescriptorA(); + // pub fn ConvertAccessToSecurityDescriptorW(); + // pub fn ConvertSDToStringSDDomainW(); + // pub fn ConvertSDToStringSDRootDomainA(); + // pub fn ConvertSDToStringSDRootDomainW(); + // pub fn ConvertSecurityDescriptorToAccessA(); + // pub fn ConvertSecurityDescriptorToAccessNamedA(); + // pub fn ConvertSecurityDescriptorToAccessNamedW(); + // pub fn ConvertSecurityDescriptorToAccessW(); + // pub fn ConvertSecurityDescriptorToStringSecurityDescriptorA(); + // pub fn ConvertSecurityDescriptorToStringSecurityDescriptorW(); + // pub fn ConvertSidToStringSidA(); + // pub fn ConvertSidToStringSidW(); + // pub fn ConvertStringSDToSDDomainA(); + // pub fn ConvertStringSDToSDDomainW(); + // pub fn ConvertStringSDToSDRootDomainA(); + // pub fn ConvertStringSDToSDRootDomainW(); + // pub fn ConvertStringSecurityDescriptorToSecurityDescriptorA(); + // pub fn ConvertStringSecurityDescriptorToSecurityDescriptorW(); + // pub fn ConvertStringSidToSidA(); + // pub fn ConvertStringSidToSidW(); + // pub fn ConvertToAutoInheritPrivateObjectSecurity(); + // pub fn CopySid(); + // pub fn CreateCodeAuthzLevel(); + // pub fn CreatePrivateObjectSecurity(); + // pub fn CreatePrivateObjectSecurityEx(); + // pub fn CreatePrivateObjectSecurityWithMultipleInheritance(); + // pub fn CreateProcessAsUserA(); + // pub fn CreateProcessAsUserW(); + // pub fn CreateProcessWithLogonW(); + // pub fn CreateProcessWithTokenW(); + // pub fn CreateRestrictedToken(); + pub fn CreateServiceA( + hSCManager: SC_HANDLE, lpServiceName: LPCSTR, lpDisplayName: LPCSTR, + dwDesiredAccess: DWORD, dwServiceType: DWORD, dwStartType: DWORD, dwErrorControl: DWORD, + lpBinaryPathName: LPCSTR, lpLoadOrderGroup: LPCSTR, lpdwTagId: LPDWORD, + lpDependencies: LPCSTR, lpServiceStartName: LPCSTR, lpPassword: LPCSTR, + ) -> SC_HANDLE; + pub fn CreateServiceW( + hSCManager: SC_HANDLE, lpServiceName: LPCWSTR, lpDisplayName: LPCWSTR, + dwDesiredAccess: DWORD, dwServiceType: DWORD, dwStartType: DWORD, dwErrorControl: DWORD, + lpBinaryPathName: LPCWSTR, lpLoadOrderGroup: LPCWSTR, lpdwTagId: LPDWORD, + lpDependencies: LPCWSTR, lpServiceStartName: LPCWSTR, lpPassword: LPCWSTR, + ) -> SC_HANDLE; + // pub fn CreateTraceInstanceId(); + // pub fn CreateWellKnownSid(); + pub fn CredDeleteA(TargetName: LPCSTR, Type: DWORD, Flags: DWORD) -> BOOL; + pub fn CredDeleteW(TargetName: LPCWSTR, Type: DWORD, Flags: DWORD) -> BOOL; + // pub fn CredEnumerateA(); + // pub fn CredEnumerateW(); + // pub fn CredFindBestCredentialA(); + // pub fn CredFindBestCredentialW(); + pub fn CredFree(Buffer: PVOID); + // pub fn CredGetSessionTypes(); + // pub fn CredGetTargetInfoA(); + // pub fn CredGetTargetInfoW(); + // pub fn CredIsMarshaledCredentialA(); + // pub fn CredIsMarshaledCredentialW(); + // pub fn CredIsProtectedA(); + // pub fn CredIsProtectedW(); + // pub fn CredMarshalCredentialA(); + // pub fn CredMarshalCredentialW(); + // pub fn CredProtectA(); + // pub fn CredProtectW(); + pub fn CredReadA( + TargetName: LPCSTR, Type: DWORD, Flags: DWORD, Credential: *mut PCREDENTIALA, + ) -> BOOL; + // pub fn CredReadDomainCredentialsA(); + // pub fn CredReadDomainCredentialsW(); + pub fn CredReadW( + TargetName: LPCWSTR, Type: DWORD, Flags: DWORD, Credential: *mut PCREDENTIALW, + ) -> BOOL; + // pub fn CredRenameA(); + // pub fn CredRenameW(); + // pub fn CredUnmarshalCredentialA(); + // pub fn CredUnmarshalCredentialW(); + // pub fn CredUnprotectA(); + // pub fn CredUnprotectW(); + pub fn CredWriteA(Credential: PCREDENTIALA, Flags: DWORD) -> BOOL; + // pub fn CredWriteDomainCredentialsA(); + // pub fn CredWriteDomainCredentialsW(); + pub fn CredWriteW(Credential: PCREDENTIALW, Flags: DWORD) -> BOOL; + pub fn CryptAcquireContextA( + phProv: *mut HCRYPTPROV, szContainer: LPCSTR, szProvider: LPCSTR, dwProvType: DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptAcquireContextW( + phProv: *mut HCRYPTPROV, szContainer: LPCWSTR, szProvider: LPCWSTR, dwProvType: DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptContextAddRef(hProv: HCRYPTPROV, pdwReserved: *mut DWORD, dwFlags: DWORD) -> BOOL; + pub fn CryptCreateHash( + hProv: HCRYPTPROV, Algid: ALG_ID, hKey: HCRYPTKEY, dwFlags: DWORD, phHash: *mut HCRYPTHASH, + ) -> BOOL; + pub fn CryptDecrypt( + hKey: HCRYPTKEY, hHash: HCRYPTHASH, Final: BOOL, dwFlags: DWORD, pbData: *mut BYTE, + pdwDataLen: *mut DWORD, + ) -> BOOL; + pub fn CryptDeriveKey( + hProv: HCRYPTPROV, Algid: ALG_ID, hBaseData: HCRYPTHASH, dwFlags: DWORD, + phKey: *mut HCRYPTKEY, + ) -> BOOL; + pub fn CryptDestroyHash(hHash: HCRYPTHASH) -> BOOL; + pub fn CryptDestroyKey(hKey: HCRYPTKEY) -> BOOL; + pub fn CryptDuplicateHash( + hHash: HCRYPTHASH, pdwReserved: *mut DWORD, dwFlags: DWORD, phHash: *mut HCRYPTHASH, + ) -> BOOL; + pub fn CryptDuplicateKey( + hKey: HCRYPTKEY, pdwReserved: *mut DWORD, dwFlags: DWORD, phKey: *mut HCRYPTKEY, + ) -> BOOL; + pub fn CryptEncrypt( + hKey: HCRYPTKEY, hHash: HCRYPTHASH, Final: BOOL, dwFlags: DWORD, pbData: *mut BYTE, + pdwDataLen: *mut DWORD, dwBufLen: DWORD, + ) -> BOOL; + pub fn CryptEnumProviderTypesA( + dwIndex: DWORD, pdwReserved: *mut DWORD, dwFlags: DWORD, pdwProvType: *mut DWORD, + szTypeName: LPSTR, pcbTypeName: *mut DWORD, + ) -> BOOL; + pub fn CryptEnumProviderTypesW( + dwIndex: DWORD, pdwReserved: *mut DWORD, dwFlags: DWORD, pdwProvType: *mut DWORD, + szTypeName: LPWSTR, pcbTypeName: *mut DWORD, + ) -> BOOL; + pub fn CryptEnumProvidersA( + dwIndex: DWORD, pdwReserved: *mut DWORD, dwFlags: DWORD, pdwProvType: *mut DWORD, + szProvName: LPSTR, pcbProvName: *mut DWORD, + ) -> BOOL; + pub fn CryptEnumProvidersW( + dwIndex: DWORD, pdwReserved: *mut DWORD, dwFlags: DWORD, pdwProvType: *mut DWORD, + szProvName: LPWSTR, pcbProvName: *mut DWORD, + ) -> BOOL; + pub fn CryptExportKey( + hKey: HCRYPTKEY, hExpKey: HCRYPTKEY, dwBlobType: DWORD, dwFlags: DWORD, pbData: *mut BYTE, + pdwDataLen: *mut DWORD, + ) -> BOOL; + pub fn CryptGenKey( + hProv: HCRYPTPROV, Algid: ALG_ID, dwFlags: DWORD, phKey: *mut HCRYPTKEY, + ) -> BOOL; + pub fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: *mut BYTE) -> BOOL; + pub fn CryptGetDefaultProviderA( + dwProvType: DWORD, pdwReserved: *mut DWORD, dwFlags: DWORD, pszProvName: LPSTR, + pcbProvName: *mut DWORD, + ) -> BOOL; + pub fn CryptGetDefaultProviderW( + dwProvType: DWORD, pdwReserved: *mut DWORD, dwFlags: DWORD, pszProvName: LPWSTR, + pcbProvName: *mut DWORD, + ) -> BOOL; + pub fn CryptGetHashParam( + hHash: HCRYPTHASH, dwParam: DWORD, pbData: *mut BYTE, pdwDataLen: *mut DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptGetKeyParam( + hKey: HCRYPTKEY, dwParam: DWORD, pbData: *mut BYTE, pdwDataLen: *mut DWORD, dwFlags: DWORD, + ) -> BOOL; + pub fn CryptGetProvParam( + hProv: HCRYPTPROV, dwParam: DWORD, pbData: *mut BYTE, pdwDataLen: *mut DWORD, + dwFlags: DWORD, + ) -> BOOL; + pub fn CryptGetUserKey(hProv: HCRYPTPROV, dwKeySpec: DWORD, phUserKey: *mut HCRYPTKEY) -> BOOL; + pub fn CryptHashData( + hHash: HCRYPTHASH, pbData: *const BYTE, dwDataLen: DWORD, dwFlags: DWORD, + ) -> BOOL; + pub fn CryptHashSessionKey(hHash: HCRYPTHASH, hKey: HCRYPTKEY, dwFlags: DWORD) -> BOOL; + pub fn CryptImportKey( + hProv: HCRYPTPROV, pbData: *const BYTE, dwDataLen: DWORD, hPubKey: HCRYPTKEY, + dwFlags: DWORD, phKey: *mut HCRYPTKEY, + ) -> BOOL; + pub fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL; + pub fn CryptSetHashParam( + hHash: HCRYPTHASH, dwParam: DWORD, pbData: *const BYTE, dwFlags: DWORD, + ) -> BOOL; + pub fn CryptSetKeyParam( + hKey: HCRYPTKEY, dwParam: DWORD, pbData: *const BYTE, dwFlags: DWORD, + ) -> BOOL; + pub fn CryptSetProvParam( + hProv: HCRYPTPROV, dwParam: DWORD, pbData: *const BYTE, dwFlags: DWORD, + ) -> BOOL; + pub fn CryptSetProviderA(pszProvName: LPCSTR, dwProvType: DWORD) -> BOOL; + pub fn CryptSetProviderExA( + pszProvName: LPCSTR, dwProvType: DWORD, pdwReserved: *mut DWORD, dwFlags: DWORD, + ) -> BOOL; + pub fn CryptSetProviderExW( + pszProvName: LPCWSTR, dwProvType: DWORD, pdwReserved: *mut DWORD, dwFlags: DWORD, + ) -> BOOL; + pub fn CryptSetProviderW(pszProvName: LPCWSTR, dwProvType: DWORD) -> BOOL; + pub fn CryptSignHashA( + hHash: HCRYPTHASH, dwKeySpec: DWORD, szDescription: LPCSTR, dwFlags: DWORD, + pbSignature: *mut BYTE, pdwSigLen: *mut DWORD, + ) -> BOOL; + pub fn CryptSignHashW( + hHash: HCRYPTHASH, dwKeySpec: DWORD, szDescription: LPCWSTR, dwFlags: DWORD, + pbSignature: *mut BYTE, pdwSigLen: *mut DWORD, + ) -> BOOL; + pub fn CryptVerifySignatureA( + hHash: HCRYPTHASH, pbSignature: *const BYTE, dwSigLen: DWORD, hPubKey: HCRYPTKEY, + szDescription: LPCSTR, dwFlags: DWORD, + ) -> BOOL; + pub fn CryptVerifySignatureW( + hHash: HCRYPTHASH, pbSignature: *const BYTE, dwSigLen: DWORD, hPubKey: HCRYPTKEY, + szDescription: LPCWSTR, dwFlags: DWORD, + ) -> BOOL; + // pub fn DecryptFileA(); + // pub fn DecryptFileW(); + // pub fn DeleteAce(); + pub fn DeleteService(hService: SC_HANDLE) -> BOOL; + // pub fn DeregisterEventSource(); + // pub fn DestroyPrivateObjectSecurity(); + // pub fn DuplicateEncryptionInfoFile(); + // pub fn DuplicateToken(); + // pub fn DuplicateTokenEx(); + // pub fn ElfBackupEventLogFileA(); + // pub fn ElfBackupEventLogFileW(); + // pub fn ElfChangeNotify(); + // pub fn ElfClearEventLogFileA(); + // pub fn ElfClearEventLogFileW(); + // pub fn ElfCloseEventLog(); + // pub fn ElfDeregisterEventSource(); + // pub fn ElfFlushEventLog(); + // pub fn ElfNumberOfRecords(); + // pub fn ElfOldestRecord(); + // pub fn ElfOpenBackupEventLogA(); + // pub fn ElfOpenBackupEventLogW(); + // pub fn ElfOpenEventLogA(); + // pub fn ElfOpenEventLogW(); + // pub fn ElfReadEventLogA(); + // pub fn ElfReadEventLogW(); + // pub fn ElfRegisterEventSourceA(); + // pub fn ElfRegisterEventSourceW(); + // pub fn ElfReportEventA(); + // pub fn ElfReportEventAndSourceW(); + // pub fn ElfReportEventW(); + // pub fn EnableTrace(); + // pub fn EnableTraceEx(); + // pub fn EnableTraceEx2(); + // pub fn EncryptFileA(); + // pub fn EncryptFileW(); + // pub fn EncryptedFileKeyInfo(); + // pub fn EncryptionDisable(); + // pub fn EnumDependentServicesA(); + // pub fn EnumDependentServicesW(); + // pub fn EnumDynamicTimeZoneInformation(); + // pub fn EnumServiceGroupW(); + // pub fn EnumServicesStatusA(); + // pub fn EnumServicesStatusExA(); + // pub fn EnumServicesStatusExW(); + // pub fn EnumServicesStatusW(); + // pub fn EnumerateTraceGuids(); + // pub fn EnumerateTraceGuidsEx(); + // pub fn EqualDomainSid(); + // pub fn EqualPrefixSid(); + // pub fn EqualSid(); + // pub fn EtwLogSysConfigExtension(); + // pub fn EventAccessControl(); + // pub fn EventAccessQuery(); + // pub fn EventAccessRemove(); + // pub fn EventActivityIdControl(); + // pub fn EventEnabled(); + // pub fn EventProviderEnabled(); + // pub fn EventRegister(); + // pub fn EventSetInformation(); + // pub fn EventUnregister(); + // pub fn EventWrite(); + // pub fn EventWriteEndScenario(); + // pub fn EventWriteEx(); + // pub fn EventWriteStartScenario(); + // pub fn EventWriteString(); + // pub fn EventWriteTransfer(); + // pub fn FileEncryptionStatusA(); + // pub fn FileEncryptionStatusW(); + // pub fn FindFirstFreeAce(); + // pub fn FlushEfsCache(); + // pub fn FlushTraceA(); + // pub fn FlushTraceW(); + // pub fn FreeEncryptedFileKeyInfo(); + // pub fn FreeEncryptedFileMetadata(); + // pub fn FreeEncryptionCertificateHashList(); + // pub fn FreeInheritedFromArray(); + // pub fn FreeSid(); + // pub fn GetAccessPermissionsForObjectA(); + // pub fn GetAccessPermissionsForObjectW(); + // pub fn GetAce(); + // pub fn GetAclInformation(); + // pub fn GetAuditedPermissionsFromAclA(); + // pub fn GetAuditedPermissionsFromAclW(); + pub fn GetCurrentHwProfileA(lpHwProfileInfo: LPHW_PROFILE_INFOA) -> BOOL; + pub fn GetCurrentHwProfileW(lpHwProfileInfo: LPHW_PROFILE_INFOW) -> BOOL; + // pub fn GetDynamicTimeZoneInformationEffectiveYears(); + // pub fn GetEffectiveRightsFromAclA(); + // pub fn GetEffectiveRightsFromAclW(); + // pub fn GetEncryptedFileMetadata(); + // pub fn GetEventLogInformation(); + // pub fn GetExplicitEntriesFromAclA(); + // pub fn GetExplicitEntriesFromAclW(); + // pub fn GetFileSecurityA(); + // pub fn GetFileSecurityW(); + // pub fn GetInformationCodeAuthzLevelW(); + // pub fn GetInformationCodeAuthzPolicyW(); + // pub fn GetInheritanceSourceA(); + // pub fn GetInheritanceSourceW(); + // pub fn GetKernelObjectSecurity(); + // pub fn GetLengthSid(); + // pub fn GetLocalManagedApplicationData(); + // pub fn GetLocalManagedApplications(); + // pub fn GetManagedApplicationCategories(); + // pub fn GetManagedApplications(); + // pub fn GetMultipleTrusteeA(); + // pub fn GetMultipleTrusteeOperationA(); + // pub fn GetMultipleTrusteeOperationW(); + // pub fn GetMultipleTrusteeW(); + // pub fn GetNamedSecurityInfoA(); + // pub fn GetNamedSecurityInfoExA(); + // pub fn GetNamedSecurityInfoExW(); + // pub fn GetNamedSecurityInfoW(); + // pub fn GetNumberOfEventLogRecords(); + // pub fn GetOldestEventLogRecord(); + // pub fn GetOverlappedAccessResults(); + // pub fn GetPrivateObjectSecurity(); + // pub fn GetSecurityDescriptorControl(); + // pub fn GetSecurityDescriptorDacl(); + // pub fn GetSecurityDescriptorGroup(); + // pub fn GetSecurityDescriptorLength(); + // pub fn GetSecurityDescriptorOwner(); + // pub fn GetSecurityDescriptorRMControl(); + // pub fn GetSecurityDescriptorSacl(); + // pub fn GetSecurityInfo(); + // pub fn GetSecurityInfoExA(); + // pub fn GetSecurityInfoExW(); + // pub fn GetServiceDisplayNameA(); + // pub fn GetServiceDisplayNameW(); + // pub fn GetServiceKeyNameA(); + // pub fn GetServiceKeyNameW(); + // pub fn GetSidIdentifierAuthority(); + // pub fn GetSidLengthRequired(); + // pub fn GetSidSubAuthority(); + // pub fn GetSidSubAuthorityCount(); + // pub fn GetStringConditionFromBinary(); + // pub fn GetThreadWaitChain(); + // pub fn GetTokenInformation(); + // pub fn GetTraceEnableFlags(); + // pub fn GetTraceEnableLevel(); + // pub fn GetTraceLoggerHandle(); + // pub fn GetTrusteeFormA(); + // pub fn GetTrusteeFormW(); + // pub fn GetTrusteeNameA(); + // pub fn GetTrusteeNameW(); + // pub fn GetTrusteeTypeA(); + // pub fn GetTrusteeTypeW(); + pub fn GetUserNameA(lpBuffer: LPSTR, pcbBuffer: LPDWORD) -> BOOL; + pub fn GetUserNameW(lpBuffer: LPWSTR, pcbBuffer: LPDWORD) -> BOOL; + // pub fn GetWindowsAccountDomainSid(); + // pub fn I_ScSetServiceBitsA(); + // pub fn I_ScSetServiceBitsW(); + // pub fn IdentifyCodeAuthzLevelW(); + // pub fn ImpersonateAnonymousToken(); + // pub fn ImpersonateLoggedOnUser(); + // pub fn ImpersonateNamedPipeClient(); + // pub fn ImpersonateSelf(); + // pub fn InitializeAcl(); + // pub fn InitializeSecurityDescriptor(); + // pub fn InitializeSid(); + // pub fn InitiateShutdownA(); + // pub fn InitiateShutdownW(); + // pub fn InitiateSystemShutdownA(); + // pub fn InitiateSystemShutdownExA(); + // pub fn InitiateSystemShutdownExW(); + // pub fn InitiateSystemShutdownW(); + // pub fn InstallApplication(); + // pub fn IsTextUnicode(); + // pub fn IsTokenRestricted(); + // pub fn IsTokenUntrusted(); + // pub fn IsValidAcl(); + // pub fn IsValidRelativeSecurityDescriptor(); + // pub fn IsValidSecurityDescriptor(); + // pub fn IsValidSid(); + // pub fn IsWellKnownSid(); + // pub fn LockServiceDatabase(); + // pub fn LogonUserA(); + // pub fn LogonUserExA(); + // pub fn LogonUserExExW(); + // pub fn LogonUserExW(); + // pub fn LogonUserW(); + // pub fn LookupAccountNameA(); + // pub fn LookupAccountNameW(); + // pub fn LookupAccountSidA(); + // pub fn LookupAccountSidW(); + // pub fn LookupPrivilegeDisplayNameA(); + // pub fn LookupPrivilegeDisplayNameW(); + pub fn LookupPrivilegeNameA( + lpSystemName: LPCSTR, lpLuid: PLUID, lpName: LPSTR, cchName: LPDWORD, + ) -> BOOL; + pub fn LookupPrivilegeNameW( + lpSystemName: LPCWSTR, lpLuid: PLUID, lpName: LPWSTR, cchName: LPDWORD, + ) -> BOOL; + pub fn LookupPrivilegeValueA( + lpSystemName: LPCSTR, lpName: LPCSTR, lpLuid: PLUID, + ) -> BOOL; + pub fn LookupPrivilegeValueW( + lpSystemName: LPCWSTR, lpName: LPCWSTR, lpLuid: PLUID, + ) -> BOOL; + // pub fn LookupSecurityDescriptorPartsA(); + // pub fn LookupSecurityDescriptorPartsW(); + // pub fn LsaAddAccountRights(); + // pub fn LsaAddPrivilegesToAccount(); + // pub fn LsaClearAuditLog(); + // pub fn LsaClose(); + // pub fn LsaCreateAccount(); + // pub fn LsaCreateSecret(); + // pub fn LsaCreateTrustedDomain(); + // pub fn LsaCreateTrustedDomainEx(); + // pub fn LsaDelete(); + // pub fn LsaDeleteTrustedDomain(); + // pub fn LsaEnumerateAccountRights(); + // pub fn LsaEnumerateAccounts(); + // pub fn LsaEnumerateAccountsWithUserRight(); + // pub fn LsaEnumeratePrivileges(); + // pub fn LsaEnumeratePrivilegesOfAccount(); + // pub fn LsaEnumerateTrustedDomains(); + // pub fn LsaEnumerateTrustedDomainsEx(); + // pub fn LsaFreeMemory(); + // pub fn LsaGetAppliedCAPIDs(); + // pub fn LsaGetQuotasForAccount(); + // pub fn LsaGetRemoteUserName(); + // pub fn LsaGetSystemAccessAccount(); + // pub fn LsaGetUserName(); + // pub fn LsaICLookupNames(); + // pub fn LsaICLookupNamesWithCreds(); + // pub fn LsaICLookupSids(); + // pub fn LsaICLookupSidsWithCreds(); + // pub fn LsaLookupNames(); + // pub fn LsaLookupNames2(); + // pub fn LsaLookupPrivilegeDisplayName(); + // pub fn LsaLookupPrivilegeName(); + // pub fn LsaLookupPrivilegeValue(); + // pub fn LsaLookupSids(); + // pub fn LsaLookupSids2(); + // pub fn LsaManageSidNameMapping(); + // pub fn LsaNtStatusToWinError(); + // pub fn LsaOpenAccount(); + // pub fn LsaOpenPolicy(); + // pub fn LsaOpenPolicySce(); + // pub fn LsaOpenSecret(); + // pub fn LsaOpenTrustedDomain(); + // pub fn LsaOpenTrustedDomainByName(); + // pub fn LsaQueryCAPs(); + // pub fn LsaQueryDomainInformationPolicy(); + // pub fn LsaQueryForestTrustInformation(); + // pub fn LsaQueryInfoTrustedDomain(); + // pub fn LsaQueryInformationPolicy(); + // pub fn LsaQuerySecret(); + // pub fn LsaQuerySecurityObject(); + // pub fn LsaQueryTrustedDomainInfo(); + // pub fn LsaQueryTrustedDomainInfoByName(); + // pub fn LsaRemoveAccountRights(); + // pub fn LsaRemovePrivilegesFromAccount(); + // pub fn LsaRetrievePrivateData(); + // pub fn LsaSetCAPs(); + // pub fn LsaSetDomainInformationPolicy(); + // pub fn LsaSetForestTrustInformation(); + // pub fn LsaSetInformationPolicy(); + // pub fn LsaSetInformationTrustedDomain(); + // pub fn LsaSetQuotasForAccount(); + // pub fn LsaSetSecret(); + // pub fn LsaSetSecurityObject(); + // pub fn LsaSetSystemAccessAccount(); + // pub fn LsaSetTrustedDomainInfoByName(); + // pub fn LsaSetTrustedDomainInformation(); + // pub fn LsaStorePrivateData(); + // pub fn MIDL_user_free_Ext(); + // pub fn MSChapSrvChangePassword(); + // pub fn MSChapSrvChangePassword2(); + // pub fn MakeAbsoluteSD(); + // pub fn MakeAbsoluteSD2(); + // pub fn MakeSelfRelativeSD(); + // pub fn MapGenericMask(); + // pub fn NotifyBootConfigStatus(); + // pub fn NotifyChangeEventLog(); + // pub fn NotifyServiceStatusChange(); + // pub fn NotifyServiceStatusChangeA(); + // pub fn NotifyServiceStatusChangeW(); + // pub fn ObjectCloseAuditAlarmA(); + // pub fn ObjectCloseAuditAlarmW(); + // pub fn ObjectDeleteAuditAlarmA(); + // pub fn ObjectDeleteAuditAlarmW(); + // pub fn ObjectOpenAuditAlarmA(); + // pub fn ObjectOpenAuditAlarmW(); + // pub fn ObjectPrivilegeAuditAlarmA(); + // pub fn ObjectPrivilegeAuditAlarmW(); + // pub fn OpenBackupEventLogA(); + // pub fn OpenBackupEventLogW(); + // pub fn OpenEncryptedFileRawA(); + // pub fn OpenEncryptedFileRawW(); + // pub fn OpenEventLogA(); + // pub fn OpenEventLogW(); + pub fn OpenProcessToken( + ProcessHandle: HANDLE, DesiredAccess: DWORD, TokenHandle: PHANDLE, + ) -> BOOL; + pub fn OpenSCManagerA( + lpMachineName: LPCSTR, lpDatabaseName: LPCSTR, dwDesiredAccess: DWORD, + ) -> SC_HANDLE; + pub fn OpenSCManagerW( + lpMachineName: LPCWSTR, lpDatabaseName: LPCWSTR, dwDesiredAccess: DWORD, + ) -> SC_HANDLE; + pub fn OpenServiceA( + hSCManager: SC_HANDLE, lpServiceName: LPCSTR, dwDesiredAccess: DWORD, + ) -> SC_HANDLE; + pub fn OpenServiceW( + hSCManager: SC_HANDLE, lpServiceName: LPCWSTR, dwDesiredAccess: DWORD, + ) -> SC_HANDLE; + // pub fn OpenThreadToken(); + // pub fn OpenThreadWaitChainSession(); + // pub fn OpenTraceA(); + // pub fn OpenTraceW(); + // pub fn OperationEnd(); + // pub fn OperationStart(); + // pub fn PerfAddCounters(); + // pub fn PerfCloseQueryHandle(); + // pub fn PerfCreateInstance(); + // pub fn PerfDecrementULongCounterValue(); + // pub fn PerfDecrementULongLongCounterValue(); + // pub fn PerfDeleteCounters(); + // pub fn PerfDeleteInstance(); + // pub fn PerfEnumerateCounterSet(); + // pub fn PerfEnumerateCounterSetInstances(); + // pub fn PerfIncrementULongCounterValue(); + // pub fn PerfIncrementULongLongCounterValue(); + // pub fn PerfOpenQueryHandle(); + // pub fn PerfQueryCounterData(); + // pub fn PerfQueryCounterInfo(); + // pub fn PerfQueryCounterSetRegistrationInfo(); + // pub fn PerfQueryInstance(); + // pub fn PerfRegCloseKey(); + // pub fn PerfRegEnumKey(); + // pub fn PerfRegEnumValue(); + // pub fn PerfRegQueryInfoKey(); + // pub fn PerfRegQueryValue(); + // pub fn PerfRegSetValue(); + // pub fn PerfSetCounterRefValue(); + // pub fn PerfSetCounterSetInfo(); + // pub fn PerfSetULongCounterValue(); + // pub fn PerfSetULongLongCounterValue(); + // pub fn PerfStartProvider(); + // pub fn PerfStartProviderEx(); + // pub fn PerfStopProvider(); + // pub fn PrivilegeCheck(); + // pub fn PrivilegedServiceAuditAlarmA(); + // pub fn PrivilegedServiceAuditAlarmW(); + // pub fn ProcessTrace(); + // pub fn QueryAllTracesA(); + // pub fn QueryAllTracesW(); + // pub fn QueryRecoveryAgentsOnEncryptedFile(); + // pub fn QuerySecurityAccessMask(); + // pub fn QueryServiceConfig2A(); + // pub fn QueryServiceConfig2W(); + // pub fn QueryServiceConfigA(); + // pub fn QueryServiceConfigW(); + // pub fn QueryServiceDynamicInformation(); + // pub fn QueryServiceLockStatusA(); + // pub fn QueryServiceLockStatusW(); + // pub fn QueryServiceObjectSecurity(); + pub fn QueryServiceStatus(hService: SC_HANDLE, lpServiceStatus: LPSERVICE_STATUS) -> BOOL; + pub fn QueryServiceStatusEx( + hService: SC_HANDLE, InfoLevel: SC_STATUS_TYPE, lpBuffer: LPBYTE, cbBufSize: DWORD, + pcbBytesNeeded: LPDWORD, + ) -> BOOL; + // pub fn QueryTraceA(); + // pub fn QueryTraceW(); + // pub fn QueryUsersOnEncryptedFile(); + // pub fn ReadEncryptedFileRaw(); + // pub fn ReadEventLogA(); + // pub fn ReadEventLogW(); + pub fn RegCloseKey(hKey: HKEY) -> LONG; + pub fn RegConnectRegistryA(lpMachineName: LPCSTR, hKey: HKEY, phkResult: PHKEY) -> LONG; + // pub fn RegConnectRegistryExA(); + // pub fn RegConnectRegistryExW(); + pub fn RegConnectRegistryW(lpMachineName: LPCWSTR, hKey: HKEY, phkResult: PHKEY) -> LONG; + pub fn RegCopyTreeA(hKeySrc: HKEY, lpSubKey: LPCSTR, hKeyDest: HKEY) -> LONG; + pub fn RegCopyTreeW(hKeySrc: HKEY, lpSubKey: LPCWSTR, hKeyDest: HKEY) -> LONG; + // pub fn RegCreateKeyA(); + pub fn RegCreateKeyExA( + hKey: HKEY, lpSubKey: LPCSTR, Reserved: DWORD, lpClass: LPSTR, dwOptions: DWORD, + samDesired: REGSAM, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, phkResult: PHKEY, + lpdwDisposition: LPDWORD, + ) -> LONG; + pub fn RegCreateKeyExW( + hKey: HKEY, lpSubKey: LPCWSTR, Reserved: DWORD, lpClass: LPWSTR, dwOptions: DWORD, + samDesired: REGSAM, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, phkResult: PHKEY, + lpdwDisposition: LPDWORD, + ) -> LONG; + pub fn RegCreateKeyTransactedA( + hKey: HKEY, lpSubKey: LPCSTR, Reserved: DWORD, lpClass: LPSTR, dwOptions: DWORD, + samDesired: REGSAM, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, phkResult: PHKEY, + lpdwDisposition: LPDWORD, hTransaction: HANDLE, pExtendedParemeter: PVOID, + ) -> LONG; + pub fn RegCreateKeyTransactedW( + hKey: HKEY, lpSubKey: LPCWSTR, Reserved: DWORD, lpClass: LPWSTR, dwOptions: DWORD, + samDesired: REGSAM, lpSecurityAttributes: LPSECURITY_ATTRIBUTES, phkResult: PHKEY, + lpdwDisposition: LPDWORD, hTransaction: HANDLE, pExtendedParemeter: PVOID, + ) -> LONG; + // pub fn RegCreateKeyW(); + pub fn RegDeleteKeyA(hKey: HKEY, lpSubKey: LPCSTR) -> LONG; + pub fn RegDeleteKeyExA( + hKey: HKEY, lpSubKey: LPCSTR, samDesired: REGSAM, Reserved: DWORD, + ) -> LONG; + pub fn RegDeleteKeyExW( + hKey: HKEY, lpSubKey: LPCWSTR, samDesired: REGSAM, Reserved: DWORD, + ) -> LONG; + pub fn RegDeleteKeyTransactedA( + hKey: HKEY, lpSubKey: LPCSTR, samDesired: REGSAM, Reserved: DWORD, + hTransaction: HANDLE, pExtendedParemeter: PVOID, + ) -> LONG; + pub fn RegDeleteKeyTransactedW( + hKey: HKEY, lpSubKey: LPCWSTR, samDesired: REGSAM, Reserved: DWORD, + hTransaction: HANDLE, pExtendedParemeter: PVOID, + ) -> LONG; + pub fn RegDeleteKeyValueA(hKey: HKEY, lpSubKey: LPCSTR, lpValueName: LPCSTR) -> LONG; + pub fn RegDeleteKeyValueW(hKey: HKEY, lpSubKey: LPCWSTR, lpValueName: LPCWSTR) -> LONG; + pub fn RegDeleteKeyW(hKey: HKEY, lpSubKey: LPCWSTR) -> LONG; + pub fn RegDeleteTreeA(hKey: HKEY, lpSubKey: LPCSTR) -> LONG; + pub fn RegDeleteTreeW(hKey: HKEY, lpSubKey: LPCWSTR) -> LONG; + pub fn RegDeleteValueA(hKey: HKEY, lpValueName: LPCSTR) -> LONG; + pub fn RegDeleteValueW(hKey: HKEY, lpValueName: LPCWSTR) -> LONG; + pub fn RegDisablePredefinedCache() -> LONG; + pub fn RegDisablePredefinedCacheEx() -> LONG; + pub fn RegDisableReflectionKey(hBase: HKEY) -> LONG; + pub fn RegEnableReflectionKey(hBase: HKEY) -> LONG; + // pub fn RegEnumKeyA(); + pub fn RegEnumKeyExA( + hKey: HKEY, dwIndex: DWORD, lpName: LPSTR, lpcName: LPDWORD, lpReserved: LPDWORD, + lpClass: LPSTR, lpcClass: LPDWORD, lpftLastWriteTime: PFILETIME, + ) -> LONG; + pub fn RegEnumKeyExW( + hKey: HKEY, dwIndex: DWORD, lpName: LPWSTR, lpcName: LPDWORD, lpReserved: LPDWORD, + lpClass: LPWSTR, lpcClass: LPDWORD, lpftLastWriteTime: PFILETIME, + ) -> LONG; + // pub fn RegEnumKeyW(); + pub fn RegEnumValueA( + hKey: HKEY, dwIndex: DWORD, lpValueName: LPSTR, lpcchValueName: LPDWORD, + lpReserved: LPDWORD, lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD, + ) -> LONG; + pub fn RegEnumValueW( + hKey: HKEY, dwIndex: DWORD, lpValueName: LPWSTR, lpcchValueName: LPDWORD, + lpReserved: LPDWORD, lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD, + ) -> LONG; + pub fn RegFlushKey(hKey: HKEY) -> LONG; + // pub fn RegGetKeySecurity(); + pub fn RegGetValueA( + hkey: HKEY, lpSubKey: LPCSTR, lpValue: LPCSTR, dwFlags: DWORD, pdwType: LPDWORD, + pvData: PVOID, pcbData: LPDWORD, + ) -> LONG; + pub fn RegGetValueW( + hkey: HKEY, lpSubKey: LPCWSTR, lpValue: LPCWSTR, dwFlags: DWORD, pdwType: LPDWORD, + pvData: PVOID, pcbData: LPDWORD, + ) -> LONG; + // pub fn RegLoadAppKeyA(); + // pub fn RegLoadAppKeyW(); + // pub fn RegLoadKeyA(); + // pub fn RegLoadKeyW(); + // pub fn RegLoadMUIStringA(); + pub fn RegLoadMUIStringW( + hKey: HKEY, pszValue: LPCWSTR, pszOutBuf: LPWSTR, cbOutBuf: DWORD, pcbData: LPDWORD, + Flags: DWORD, pszDirectory: LPCWSTR, + ) -> LONG; + pub fn RegNotifyChangeKeyValue( + hKey: HKEY, bWatchSubtree: BOOL, dwNotifyFilter: DWORD, hEvent: HANDLE, + fAsynchronous: BOOL, + ) -> LONG; + pub fn RegOpenCurrentUser(samDesired: REGSAM, phkResult: PHKEY) -> LONG; + // pub fn RegOpenKeyA(); + pub fn RegOpenKeyExA( + hKey: HKEY, lpSubKey: LPCSTR, ulOptions: DWORD, samDesired: REGSAM, phkResult: PHKEY, + ) -> LONG; + pub fn RegOpenKeyExW( + hKey: HKEY, lpSubKey: LPCWSTR, ulOptions: DWORD, samDesired: REGSAM, phkResult: PHKEY, + ) -> LONG; + pub fn RegOpenKeyTransactedA( + hKey: HKEY, lpSubKey: LPCSTR, ulOptions: DWORD, samDesired: REGSAM, phkResult: PHKEY, + hTransaction: HANDLE, pExtendedParemeter: PVOID, + ) -> LONG; + pub fn RegOpenKeyTransactedW( + hKey: HKEY, lpSubKey: LPCWSTR, ulOptions: DWORD, samDesired: REGSAM, phkResult: PHKEY, + hTransaction: HANDLE, pExtendedParemeter: PVOID, + ) -> LONG; + // pub fn RegOpenKeyW(); + pub fn RegOpenUserClassesRoot( + hToken: HANDLE, dwOptions: DWORD, samDesired: REGSAM, phkResult: PHKEY, + ) -> LONG; + pub fn RegOverridePredefKey(hKey: HKEY, hNewHKey: HKEY) -> LONG; + pub fn RegQueryInfoKeyA( + hKey: HKEY, lpClass: LPSTR, lpcClass: LPDWORD, lpReserved: LPDWORD, lpcSubKeys: LPDWORD, + lpcMaxSubKeyLen: LPDWORD, lpcMaxClassLen: LPDWORD, lpcValues: LPDWORD, + lpcMaxValueNameLen: LPDWORD, lpcMaxValueLen: LPDWORD, lpcbSecurityDescriptor: LPDWORD, + lpftLastWriteTime: PFILETIME, + ) -> LONG; + pub fn RegQueryInfoKeyW( + hKey: HKEY, lpClass: LPWSTR, lpcClass: LPDWORD, lpReserved: LPDWORD, lpcSubKeys: LPDWORD, + lpcMaxSubKeyLen: LPDWORD, lpcMaxClassLen: LPDWORD, lpcValues: LPDWORD, + lpcMaxValueNameLen: LPDWORD, lpcMaxValueLen: LPDWORD, lpcbSecurityDescriptor: LPDWORD, + lpftLastWriteTime: PFILETIME, + ) -> LONG; + pub fn RegQueryMultipleValuesA( + hKey: HKEY, val_list: PVALENTA, num_vals: DWORD, lpValueBuf: LPSTR, ldwTotsize: LPDWORD, + ) -> LONG; + pub fn RegQueryMultipleValuesW( + hKey: HKEY, val_list: PVALENTW, num_vals: DWORD, lpValueBuf: LPWSTR, ldwTotsize: LPDWORD, + ) -> LONG; + pub fn RegQueryReflectionKey(hBase: HKEY, bIsReflectionDisabled: PBOOL) -> LONG; + pub fn RegQueryValueExA( + hKey: HKEY, lpValueName: LPCSTR, lpReserved: LPDWORD, lpType: LPDWORD, lpData: LPBYTE, + lpcbData: LPDWORD, + ) -> LONG; + pub fn RegQueryValueExW( + hKey: HKEY, lpValueName: LPCWSTR, lpReserved: LPDWORD, lpType: LPDWORD, lpData: LPBYTE, + lpcbData: LPDWORD, + ) -> LONG; + // pub fn RegQueryValueW(); + // pub fn RegRenameKey(); + // pub fn RegReplaceKeyA(); + // pub fn RegReplaceKeyW(); + // pub fn RegRestoreKeyA(); + // pub fn RegRestoreKeyW(); + // pub fn RegSaveKeyA(); + // pub fn RegSaveKeyExA(); + // pub fn RegSaveKeyExW(); + // pub fn RegSaveKeyW(); + // pub fn RegSetKeySecurity(); + pub fn RegSetKeyValueA( + hKey: HKEY, lpSubKey: LPCSTR, lpValueName: LPCSTR, dwType: DWORD, lpData: LPCVOID, + cbData: DWORD, + ) -> LONG; + pub fn RegSetValueExA( + hKey: HKEY, lpValueName: LPCSTR, Reserved: DWORD, dwType: DWORD, lpData: *const BYTE, + cbData: DWORD, + ) -> LONG; + pub fn RegSetValueExW( + hKey: HKEY, lpValueName: LPCWSTR, Reserved: DWORD, dwType: DWORD, lpData: *const BYTE, + cbData: DWORD, + ) -> LONG; + pub fn RegSetKeyValueW( + hKey: HKEY, lpSubKey: LPCWSTR, lpValueName: LPCWSTR, dwType: DWORD, lpData: LPCVOID, + cbData: DWORD, + ) -> LONG; + // pub fn RegUnLoadKeyA(); + // pub fn RegUnLoadKeyW(); + // pub fn RegisterEventSourceA(); + // pub fn RegisterEventSourceW(); + pub fn RegisterServiceCtrlHandlerA( + lpServiceName: LPCSTR, lpHandlerProc: LPHANDLER_FUNCTION, + ) -> SERVICE_STATUS_HANDLE; + pub fn RegisterServiceCtrlHandlerExA( + lpServiceName: LPCSTR, lpHandlerProc: LPHANDLER_FUNCTION_EX, lpContext: LPVOID, + ) -> SERVICE_STATUS_HANDLE; + pub fn RegisterServiceCtrlHandlerExW( + lpServiceName: LPCWSTR, lpHandlerProc: LPHANDLER_FUNCTION_EX, lpContext: LPVOID, + ) -> SERVICE_STATUS_HANDLE; + pub fn RegisterServiceCtrlHandlerW( + lpServiceName: LPCWSTR, lpHandlerProc: LPHANDLER_FUNCTION, + ) -> SERVICE_STATUS_HANDLE; + // pub fn RegisterTraceGuidsA(); + // pub fn RegisterTraceGuidsW(); + // pub fn RegisterWaitChainCOMCallback(); + // pub fn RemoteRegEnumKeyWrapper(); + // pub fn RemoteRegEnumValueWrapper(); + // pub fn RemoteRegQueryInfoKeyWrapper(); + // pub fn RemoteRegQueryValueWrapper(); + // pub fn RemoveTraceCallback(); + // pub fn RemoveUsersFromEncryptedFile(); + // pub fn ReportEventA(); + // pub fn ReportEventW(); + // pub fn RevertToSelf(); + // pub fn SafeBaseRegGetKeySecurity(); + // pub fn SaferCloseLevel(); + // pub fn SaferComputeTokenFromLevel(); + // pub fn SaferCreateLevel(); + // pub fn SaferGetLevelInformation(); + // pub fn SaferGetPolicyInformation(); + // pub fn SaferIdentifyLevel(); + // pub fn SaferRecordEventLogEntry(); + // pub fn SaferSetLevelInformation(); + // pub fn SaferSetPolicyInformation(); + // pub fn SaferiIsExecutableFileType(); + // pub fn SetAclInformation(); + // pub fn SetEncryptedFileMetadata(); + // pub fn SetEntriesInAccessListA(); + // pub fn SetEntriesInAccessListW(); + // pub fn SetEntriesInAclA(); + // pub fn SetEntriesInAclW(); + // pub fn SetEntriesInAuditListA(); + // pub fn SetEntriesInAuditListW(); + // pub fn SetFileSecurityA(); + // pub fn SetFileSecurityW(); + // pub fn SetInformationCodeAuthzLevelW(); + // pub fn SetInformationCodeAuthzPolicyW(); + // pub fn SetKernelObjectSecurity(); + // pub fn SetNamedSecurityInfoA(); + // pub fn SetNamedSecurityInfoExA(); + // pub fn SetNamedSecurityInfoExW(); + // pub fn SetNamedSecurityInfoW(); + // pub fn SetPrivateObjectSecurity(); + // pub fn SetPrivateObjectSecurityEx(); + // pub fn SetSecurityAccessMask(); + // pub fn SetSecurityDescriptorControl(); + // pub fn SetSecurityDescriptorDacl(); + // pub fn SetSecurityDescriptorGroup(); + // pub fn SetSecurityDescriptorOwner(); + // pub fn SetSecurityDescriptorRMControl(); + // pub fn SetSecurityDescriptorSacl(); + // pub fn SetSecurityInfo(); + // pub fn SetSecurityInfoExA(); + // pub fn SetSecurityInfoExW(); + // pub fn SetServiceBits(); + // pub fn SetServiceObjectSecurity(); + pub fn SetServiceStatus( + hServiceStatus: SERVICE_STATUS_HANDLE, lpServiceStatus: LPSERVICE_STATUS, + ) -> BOOL; + // pub fn SetThreadToken(); + // pub fn SetTokenInformation(); + // pub fn SetTraceCallback(); + // pub fn SetUserFileEncryptionKey(); + // pub fn SetUserFileEncryptionKeyEx(); + // pub fn StartServiceA(); + pub fn StartServiceCtrlDispatcherA(lpServiceStartTable: *const SERVICE_TABLE_ENTRYA) -> BOOL; + pub fn StartServiceCtrlDispatcherW(lpServiceStartTable: *const SERVICE_TABLE_ENTRYW) -> BOOL; + // pub fn StartServiceW(); + // pub fn StartTraceA(); + // pub fn StartTraceW(); + // pub fn StopTraceA(); + // pub fn StopTraceW(); + // pub fn SystemFunction001(); + // pub fn SystemFunction002(); + // pub fn SystemFunction003(); + // pub fn SystemFunction004(); + // pub fn SystemFunction005(); + // pub fn SystemFunction006(); + // pub fn SystemFunction007(); + // pub fn SystemFunction008(); + // pub fn SystemFunction009(); + // pub fn SystemFunction010(); + // pub fn SystemFunction011(); + // pub fn SystemFunction012(); + // pub fn SystemFunction013(); + // pub fn SystemFunction014(); + // pub fn SystemFunction015(); + // pub fn SystemFunction016(); + // pub fn SystemFunction017(); + // pub fn SystemFunction018(); + // pub fn SystemFunction019(); + // pub fn SystemFunction020(); + // pub fn SystemFunction021(); + // pub fn SystemFunction022(); + // pub fn SystemFunction023(); + // pub fn SystemFunction024(); + // pub fn SystemFunction025(); + // pub fn SystemFunction026(); + // pub fn SystemFunction027(); + // pub fn SystemFunction028(); + // pub fn SystemFunction029(); + // pub fn SystemFunction030(); + // pub fn SystemFunction031(); + // pub fn SystemFunction032(); + // pub fn SystemFunction033(); + // pub fn SystemFunction034(); + // pub fn SystemFunction036(); + // pub fn SystemFunction040(); + // pub fn SystemFunction041(); + // pub fn TraceEvent(); + // pub fn TraceEventInstance(); + // pub fn TraceMessage(); + // pub fn TraceMessageVa(); + // pub fn TraceQueryInformation(); + // pub fn TraceSetInformation(); + // pub fn TreeResetNamedSecurityInfoA(); + // pub fn TreeResetNamedSecurityInfoW(); + // pub fn TreeSetNamedSecurityInfoA(); + // pub fn TreeSetNamedSecurityInfoW(); + // pub fn TrusteeAccessToObjectA(); + // pub fn TrusteeAccessToObjectW(); + // pub fn UninstallApplication(); + // pub fn UnlockServiceDatabase(); + // pub fn UnregisterTraceGuids(); + // pub fn UpdateTraceA(); + // pub fn UpdateTraceW(); + // pub fn UsePinForEncryptedFilesA(); + // pub fn UsePinForEncryptedFilesW(); + // pub fn WaitServiceState(); + // pub fn WriteEncryptedFileRaw(); +} diff --git a/aho-corasick-0.5.3/.cargo-checksum.json b/aho-corasick-0.5.3/.cargo-checksum.json new file mode 100644 index 000000000..aee687767 --- /dev/null +++ b/aho-corasick-0.5.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"} \ No newline at end of file diff --git a/aho-corasick-0.5.3/.travis.yml b/aho-corasick-0.5.3/.travis.yml new file mode 100644 index 000000000..e8380b851 --- /dev/null +++ b/aho-corasick-0.5.3/.travis.yml @@ -0,0 +1,12 @@ +language: rust +rust: + - stable + - beta + - nightly +script: + - cargo build --verbose + - cargo test --verbose + - cargo doc + - if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then + cargo bench --verbose; + fi diff --git a/aho-corasick-0.5.3/COPYING b/aho-corasick-0.5.3/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/aho-corasick-0.5.3/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/aho-corasick-0.5.3/Cargo.toml b/aho-corasick-0.5.3/Cargo.toml new file mode 100644 index 000000000..e4d42d0fd --- /dev/null +++ b/aho-corasick-0.5.3/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "aho-corasick" +version = "0.5.3" #:version +authors = ["Andrew Gallant "] +description = "Fast multiple substring searching with finite state machines." +documentation = "http://burntsushi.net/rustdoc/aho_corasick/" +homepage = "https://github.com/BurntSushi/aho-corasick" +repository = "https://github.com/BurntSushi/aho-corasick" +readme = "README.md" +keywords = ["string", "search", "text", "aho", "corasick"] +license = "Unlicense/MIT" + +[lib] +name = "aho_corasick" + +[[bin]] +name = "aho-corasick-dot" +test = false +doc = false +bench = false + +[dependencies] +memchr = "0.1.9" + +[dev-dependencies] +csv = "0.14" +docopt = "0.6" +memmap = "0.2" +quickcheck = "0.2" +rand = "0.3" +rustc-serialize = "0.3" + +[[bench]] +name = "bench" +path = "benches/bench.rs" +test = false +bench = true + +[profile.test] +debug = true + +[profile.bench] +debug = true + +[profile.release] +debug = true diff --git a/aho-corasick-0.5.3/LICENSE-MIT b/aho-corasick-0.5.3/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/aho-corasick-0.5.3/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/aho-corasick-0.5.3/Makefile b/aho-corasick-0.5.3/Makefile new file mode 100644 index 000000000..9f956f4c4 --- /dev/null +++ b/aho-corasick-0.5.3/Makefile @@ -0,0 +1,14 @@ +all: + echo Nothing to do... + +ctags: + ctags --recurse --options=ctags.rust --languages=Rust + +docs: + cargo doc + in-dir ./target/doc fix-perms + rscp ./target/doc/* gopher:~/www/burntsushi.net/rustdoc/ + +push: + git push origin master + git push github master diff --git a/aho-corasick-0.5.3/README.md b/aho-corasick-0.5.3/README.md new file mode 100644 index 000000000..604cd3d68 --- /dev/null +++ b/aho-corasick-0.5.3/README.md @@ -0,0 +1,55 @@ +This crate provides an implementation of the +[Aho-Corasick](http://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm) +algorithm. Its intended use case is for fast substring matching, particularly +when matching multiple substrings in a search text. This is achieved by +compiling the substrings into a finite state machine. + +This implementation provides optimal algorithmic time complexity. Construction +of the finite state machine is `O(p)` where `p` is the length of the substrings +concatenated. Matching against search text is `O(n + p + m)`, where `n` is +the length of the search text and `m` is the number of matches. + +[![Build status](https://api.travis-ci.org/BurntSushi/aho-corasick.png)](https://travis-ci.org/BurntSushi/aho-corasick) +[![](http://meritbadge.herokuapp.com/aho-corasick)](https://crates.io/crates/aho-corasick) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + + +### Documentation + +[http://burntsushi.net/rustdoc/aho_corasick/](http://burntsushi.net/rustdoc/aho_corasick/). + + +### Example + +The documentation contains several examples, and there is a more complete +example as a full program in `examples/dict-search.rs`. + +Here is a quick example showing simple substring matching: + +```rust +use aho_corasick::{Automaton, AcAutomaton, Match}; + +let aut = AcAutomaton::new(vec!["apple", "maple"]); +let mut it = aut.find("I like maple apples."); +assert_eq!(it.next(), Some(Match { + pati: 1, + start: 7, + end: 12, +})); +assert_eq!(it.next(), Some(Match { + pati: 0, + start: 13, + end: 18, +})); +assert_eq!(it.next(), None); +``` + + +### Alternatives + +Aho-Corasick is useful for matching multiple substrings against many long +strings. If your long string is fixed, then you might consider building a +[suffix array](https://github.com/BurntSushi/suffix) +of the search text (which takes `O(n)` time). Matches can then be found in +`O(plogn)` time. diff --git a/aho-corasick-0.5.3/UNLICENSE b/aho-corasick-0.5.3/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/aho-corasick-0.5.3/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/aho-corasick-0.5.3/benches/bench.rs b/aho-corasick-0.5.3/benches/bench.rs new file mode 100644 index 000000000..d51bcaeec --- /dev/null +++ b/aho-corasick-0.5.3/benches/bench.rs @@ -0,0 +1,339 @@ +#![feature(test)] + +extern crate aho_corasick; +extern crate test; + +use std::iter; + +use aho_corasick::{Automaton, AcAutomaton, Transitions}; +use test::Bencher; + +const HAYSTACK_RANDOM: &'static str = include_str!("random.txt"); +const HAYSTACK_SHERLOCK: &'static str = include_str!("sherlock.txt"); + +fn bench_aut_no_match, T: Transitions>( + b: &mut Bencher, + aut: AcAutomaton, + haystack: &str, +) { + b.bytes = haystack.len() as u64; + b.iter(|| assert!(aut.find(haystack).next().is_none())); +} + +fn bench_box_aut_no_match, T: Transitions>( + b: &mut Bencher, + aut: AcAutomaton, + haystack: &str, +) { + b.bytes = haystack.len() as u64; + let aut: &Automaton

= &aut; + b.iter(|| assert!(Automaton::find(&aut, haystack).next().is_none())); +} + +fn bench_full_aut_no_match, T: Transitions>( + b: &mut Bencher, + aut: AcAutomaton, + haystack: &str, +) { + let aut = aut.into_full(); + b.bytes = haystack.len() as u64; + b.iter(|| assert!(aut.find(haystack).next().is_none())); +} + +fn bench_full_aut_overlapping_no_match, T: Transitions>( + b: &mut Bencher, + aut: AcAutomaton, + haystack: &str, +) { + let aut = aut.into_full(); + b.bytes = haystack.len() as u64; + b.iter(|| assert!(aut.find_overlapping(haystack).count() == 0)); +} + +fn bench_naive_no_match(b: &mut Bencher, needles: Vec, haystack: &str) + where S: Into { + b.bytes = haystack.len() as u64; + let needles: Vec = needles.into_iter().map(Into::into).collect(); + b.iter(|| assert!(!naive_find(&needles, haystack))); +} + +fn haystack_same(letter: char) -> String { + iter::repeat(letter).take(10000).collect() +} + +macro_rules! aut_benches { + ($prefix:ident, $aut:expr, $bench:expr) => { + mod $prefix { +#![allow(unused_imports)] +use aho_corasick::{Automaton, AcAutomaton, Sparse}; +use test::Bencher; + +use super::{ + HAYSTACK_RANDOM, haystack_same, + bench_aut_no_match, bench_box_aut_no_match, + bench_full_aut_no_match, bench_full_aut_overlapping_no_match, +}; + +#[bench] +fn ac_one_byte(b: &mut Bencher) { + let aut = $aut(vec!["a"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_one_prefix_byte_no_match(b: &mut Bencher) { + let aut = $aut(vec!["zbc"]); + $bench(b, aut, &haystack_same('y')); +} + +#[bench] +fn ac_one_prefix_byte_every_match(b: &mut Bencher) { + // We lose the benefit of `memchr` because the first byte matches + // in every position in the haystack. + let aut = $aut(vec!["zbc"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_one_prefix_byte_random(b: &mut Bencher) { + let aut = $aut(vec!["zbc\x00"]); + $bench(b, aut, HAYSTACK_RANDOM); +} + +#[bench] +fn ac_two_bytes(b: &mut Bencher) { + let aut = $aut(vec!["a", "b"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_two_diff_prefix(b: &mut Bencher) { + let aut = $aut(vec!["abcdef", "bmnopq"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_two_one_prefix_byte_every_match(b: &mut Bencher) { + let aut = $aut(vec!["zbcdef", "zmnopq"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_two_one_prefix_byte_no_match(b: &mut Bencher) { + let aut = $aut(vec!["zbcdef", "zmnopq"]); + $bench(b, aut, &haystack_same('y')); +} + +#[bench] +fn ac_two_one_prefix_byte_random(b: &mut Bencher) { + let aut = $aut(vec!["zbcdef\x00", "zmnopq\x00"]); + $bench(b, aut, HAYSTACK_RANDOM); +} + +#[bench] +fn ac_ten_bytes(b: &mut Bencher) { + let aut = $aut(vec!["a", "b", "c", "d", "e", + "f", "g", "h", "i", "j"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_ten_diff_prefix(b: &mut Bencher) { + let aut = $aut(vec!["abcdef", "bbcdef", "cbcdef", "dbcdef", + "ebcdef", "fbcdef", "gbcdef", "hbcdef", + "ibcdef", "jbcdef"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_ten_one_prefix_byte_every_match(b: &mut Bencher) { + let aut = $aut(vec!["zacdef", "zbcdef", "zccdef", "zdcdef", + "zecdef", "zfcdef", "zgcdef", "zhcdef", + "zicdef", "zjcdef"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_ten_one_prefix_byte_no_match(b: &mut Bencher) { + let aut = $aut(vec!["zacdef", "zbcdef", "zccdef", "zdcdef", + "zecdef", "zfcdef", "zgcdef", "zhcdef", + "zicdef", "zjcdef"]); + $bench(b, aut, &haystack_same('y')); +} + +#[bench] +fn ac_ten_one_prefix_byte_random(b: &mut Bencher) { + let aut = $aut(vec!["zacdef\x00", "zbcdef\x00", "zccdef\x00", + "zdcdef\x00", "zecdef\x00", "zfcdef\x00", + "zgcdef\x00", "zhcdef\x00", "zicdef\x00", + "zjcdef\x00"]); + $bench(b, aut, HAYSTACK_RANDOM); +} + } + } +} + +aut_benches!(dense, AcAutomaton::new, bench_aut_no_match); +aut_benches!(dense_boxed, AcAutomaton::new, bench_box_aut_no_match); +aut_benches!(sparse, AcAutomaton::<&str, Sparse>::with_transitions, + bench_aut_no_match); +aut_benches!(full, AcAutomaton::new, bench_full_aut_no_match); +aut_benches!(full_overlap, AcAutomaton::new, bench_full_aut_overlapping_no_match); + +// A naive multi-pattern search. +// We use this to benchmark *throughput*, so it should never match anything. +fn naive_find(needles: &[String], haystack: &str) -> bool { + for hi in 0..haystack.len() { + let rest = &haystack.as_bytes()[hi..]; + for needle in needles { + let needle = needle.as_bytes(); + if needle.len() > rest.len() { + continue; + } + if needle == &rest[..needle.len()] { + // should never happen in throughput benchmarks. + return true; + } + } + } + false +} + +#[bench] +fn naive_one_byte(b: &mut Bencher) { + bench_naive_no_match(b, vec!["a"], &haystack_same('z')); +} + +#[bench] +fn naive_one_prefix_byte_no_match(b: &mut Bencher) { + bench_naive_no_match(b, vec!["zbc"], &haystack_same('y')); +} + +#[bench] +fn naive_one_prefix_byte_every_match(b: &mut Bencher) { + bench_naive_no_match(b, vec!["zbc"], &haystack_same('z')); +} + +#[bench] +fn naive_one_prefix_byte_random(b: &mut Bencher) { + bench_naive_no_match(b, vec!["zbc\x00"], HAYSTACK_RANDOM); +} + +#[bench] +fn naive_two_bytes(b: &mut Bencher) { + bench_naive_no_match(b, vec!["a", "b"], &haystack_same('z')); +} + +#[bench] +fn naive_two_diff_prefix(b: &mut Bencher) { + bench_naive_no_match(b, vec!["abcdef", "bmnopq"], &haystack_same('z')); +} + +#[bench] +fn naive_two_one_prefix_byte_every_match(b: &mut Bencher) { + bench_naive_no_match(b, vec!["zbcdef", "zmnopq"], &haystack_same('z')); +} + +#[bench] +fn naive_two_one_prefix_byte_no_match(b: &mut Bencher) { + bench_naive_no_match(b, vec!["zbcdef", "zmnopq"], &haystack_same('y')); +} + +#[bench] +fn naive_two_one_prefix_byte_random(b: &mut Bencher) { + bench_naive_no_match(b, vec!["zbcdef\x00", "zmnopq\x00"], HAYSTACK_RANDOM); +} + +#[bench] +fn naive_ten_bytes(b: &mut Bencher) { + let needles = vec!["a", "b", "c", "d", "e", + "f", "g", "h", "i", "j"]; + bench_naive_no_match(b, needles, &haystack_same('z')); +} + +#[bench] +fn naive_ten_diff_prefix(b: &mut Bencher) { + let needles = vec!["abcdef", "bbcdef", "cbcdef", "dbcdef", + "ebcdef", "fbcdef", "gbcdef", "hbcdef", + "ibcdef", "jbcdef"]; + bench_naive_no_match(b, needles, &haystack_same('z')); +} + +#[bench] +fn naive_ten_one_prefix_byte_every_match(b: &mut Bencher) { + let needles = vec!["zacdef", "zbcdef", "zccdef", "zdcdef", + "zecdef", "zfcdef", "zgcdef", "zhcdef", + "zicdef", "zjcdef"]; + bench_naive_no_match(b, needles, &haystack_same('z')); +} + +#[bench] +fn naive_ten_one_prefix_byte_no_match(b: &mut Bencher) { + let needles = vec!["zacdef", "zbcdef", "zccdef", "zdcdef", + "zecdef", "zfcdef", "zgcdef", "zhcdef", + "zicdef", "zjcdef"]; + bench_naive_no_match(b, needles, &haystack_same('y')); +} + +#[bench] +fn naive_ten_one_prefix_byte_random(b: &mut Bencher) { + let needles = vec!["zacdef\x00", "zbcdef\x00", "zccdef\x00", + "zdcdef\x00", "zecdef\x00", "zfcdef\x00", + "zgcdef\x00", "zhcdef\x00", "zicdef\x00", + "zjcdef\x00"]; + bench_naive_no_match(b, needles, HAYSTACK_RANDOM); +} + + +// The organization above is just awful. Let's start over... + +mod sherlock { + use aho_corasick::{Automaton, AcAutomaton}; + use test::Bencher; + use super::HAYSTACK_SHERLOCK; + + macro_rules! sherlock { + ($name:ident, $count:expr, $pats:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let haystack = HAYSTACK_SHERLOCK; + let aut = AcAutomaton::new($pats).into_full(); + b.bytes = haystack.len() as u64; + b.iter(|| assert_eq!($count, aut.find(haystack).count())); + } + } + } + + sherlock!(name_alt1, 158, vec!["Sherlock", "Street"]); + + sherlock!(name_alt2, 558, vec!["Sherlock", "Holmes"]); + + sherlock!(name_alt3, 740, vec![ + "Sherlock", "Holmes", "Watson", "Irene", "Adler", "John", "Baker", + ]); + + sherlock!(name_alt3_nocase, 1764, vec![ + "ADL", "ADl", "AdL", "Adl", "BAK", "BAk", "BAK", "BaK", "Bak", "BaK", + "HOL", "HOl", "HoL", "Hol", "IRE", "IRe", "IrE", "Ire", "JOH", "JOh", + "JoH", "Joh", "SHE", "SHe", "ShE", "She", "WAT", "WAt", "WaT", "Wat", + "aDL", "aDl", "adL", "adl", "bAK", "bAk", "bAK", "baK", "bak", "baK", + "hOL", "hOl", "hoL", "hol", "iRE", "iRe", "irE", "ire", "jOH", "jOh", + "joH", "joh", "sHE", "sHe", "shE", "she", "wAT", "wAt", "waT", "wat", + "ſHE", "ſHe", "ſhE", "ſhe", + ]); + + sherlock!(name_alt4, 582, vec!["Sher", "Hol"]); + + sherlock!(name_alt4_nocase, 1307, vec![ + "HOL", "HOl", "HoL", "Hol", "SHE", "SHe", "ShE", "She", "hOL", "hOl", + "hoL", "hol", "sHE", "sHe", "shE", "she", "ſHE", "ſHe", "ſhE", "ſhe", + ]); + + sherlock!(name_alt5, 639, vec!["Sherlock", "Holmes", "Watson"]); + + sherlock!(name_alt5_nocase, 1442, vec![ + "HOL", "HOl", "HoL", "Hol", "SHE", "SHe", "ShE", "She", "WAT", "WAt", + "WaT", "Wat", "hOL", "hOl", "hoL", "hol", "sHE", "sHe", "shE", "she", + "wAT", "wAt", "waT", "wat", "ſHE", "ſHe", "ſhE", "ſhe", + ]); +} diff --git a/aho-corasick-0.5.3/benches/random.txt b/aho-corasick-0.5.3/benches/random.txt new file mode 100644 index 000000000..dfae5cd14 --- /dev/null +++ b/aho-corasick-0.5.3/benches/random.txt @@ -0,0 +1,513 @@ + +mnxnsynfvuugtbxsxbfxwreuspglnplefzwsp +tacfqcwnmodnmgnyiuvqoco +z + +qjuozfkexn +zoaxzncje +sldhqtmgxzyurfyzwazmmu +bbeuv +mzsrihycwcb +xzfqozfmlnpmrzpxxxytqs +xrg +mcplby +nmslhfgjowhzfxsvyddydnsyehdskbydbjksqtpet +indvfw +bvjvvw + +pddufodyqtyixbndtumndyz +xjjhtuvmsxhuwqulqtjhqrdqrmtbcphvyuqllocrnkpfv +zemshhz +wss +xewlrxfmgxnwgphcgefa +mbgsgbzrtthxweimcqzcaaheurdmd +osqefupespvh +z +tvvlakwzwjbrgjzfgubsmmonav +pjdskxcfgapsm +zqktqgkrcdrlskx +zwwfebhguskho +zlvvw +czwm +gojnpmboehlsazbexjjnuscqftrfufngygjdxcydib +d +afigycivicnknfxl +ljuwuopctiftfwctxecwipjnljyef +jonwbkodomzhqvlf +jdkizhognqsdogunwedjsmsdzho +zxvni +oynfjf +muvokjuqz +azuwrwtuxzfopwrcex +ixrjinlvxjmn +blaegnmbhsgsbmebwazaeguugtkowexgnqtbfkldadddv +tzabyoftyov +ctbtqbzscxzviuvcigwuwusrdro +ljynr +gnnnyyxslrhsbj +hhzlw +hijalf +rxlfqk +mhaofforwznvmcgplinludpgkucpa +gvvxsqqfmu +xxqhoyosixjfhjuxpv +faadjpvamjekreepizurntvwdynozfawsfawyms + +lcbutr +aqyxvpozkjrecrkl +lfmochahrr +ptqyomjlwo +vcmslulznx +lmlsskcihrmxauztuarydlp +beiqsrfnmvmlmybmwpektjbikvpggthpabqsgmjhnthvysuhwbigillugjsp +dfsuegseffwcsnvsrqedytblbpzbfeyfsq +kypvqctrkuds +ylqeduokzgdqaxelhftxnxbidu +bprzyayfopxdsmfhhfqowa +ymiutdtlfaaxpbtaeslv +ggago + +owpbicekdeykzfgcbgzobdvvrtetvcv +xsrlgingstiez +gyncqvq +xasohmeiwyscpehctmzmsnjklg +xsudghakxlw +dzqlfptjogzpkvwuticcyugnyopypuqqc +wlxshxbhdvuherumoppcc + +znyaptivzncvkpeyeipynqefjxjjcsgfqbnezeebtowdrbjaqjlbxwvyikrmxjwoxngqgvfpbniftnmszuxg +umwpwwyvufy +pallkjtnrmtauqxauewgygwkjjwebbkabhtxticxmxfujpxlrpzlrozfslkzfdsswlmmsbdgjwmjnummk +dhsxylejzityahtqqzmohrpzjprrsraztpnuagtyzfjdekthvdogfidksrdppr +ybc +fyukknoqfnkllkwflwempjijxgo +dltvlau +rhvrvlwsribfctuzodfqkdczfzxnetqqzflnhiyl +goxmcasmq +wljbhwkpahdotqhhrbhqzijv +lszewkgdmkezvgmbmllhpksdkoiwgkvqjmurshrptlctqsosuurndcuzjfwherotv +dudxxihygxblhgchbgzyzffb +eht +fvwxvqoltdcsd +rkuig +e +axhsacsmnicugul +rubtdlhjqndxdzzwfnkuzy +swxteuyxxsktkjgv +hzwwodlqaq +vxgecev +qnwla +vdxjuzpyoqhpmuunyffptopmeauhycs +dkzo +awrfzatzohslgvqlaezepmli +qgxatixvpkkhvkumbwmwcagtgyfljdok +amdnzstpvcqj +xsrvwvhjirzfgkessve +qezwbfltfbikbmoasvoflozsjhrljnszqiciuqmflrlqowwkoevuumh +babskcvavmtvsxqsewirucwzajjcfcqwsydydqo +ywfurpsl +edacsjjkjjewkxfoh +dcgkfpcjezurnuhiatrczcp +xsatnimwbcciu +grzmbrsvvcyigcbmcqfwiiknrohveubhyijxeyzfm +kqyewccgcqrrrznwxmoztlyseagbpyho +najju +nis +awgzdvfjkzlrsjcqfeacx +oisuflfigrjaex +desbdulyuwqxuxianyypybxwlql +ekmqgspvqpftpwswayh +egbyj +fznzprhvnnwcxgcc +wfdsueieosmugirxbymbpmfrspvrktjzguxm +qkjrufshwnfwwpbhukdjlaqvljlgubmqmhnha +hwqpudgnblhlxppbrmbznotteivuzguuwlhtkytky +w +yofkyzbpg +cenolnfnllkvhikrpttcxgqxmufvorekjruyjxmr + +hyexmpjijgzumawp +cdbevdilgopbzlo +fivelagckslkugdxprjxkylizewcptwxfhomzuituujixchadmnjoktnqa +csojvlinzmmkkfzqueamnuwkanzdzsavgohposbuoamoevehqrmcxdsuyelvvctoejzoertqormhaaxwofvjzekwt +sbkghhnhutrvwtyjaxndzyjamrhx +jjyqy +majwbnrhveuhrsbbbjrwpwuplifeseylqh +wyvutpxnkrnkuxxetjkkifpqb +dyzucmbcvgnjeecm +hz +uhnuipthxrzkqluosvk +lwqqzsdwiwvwaqfwlvubadlyizlo +jbd +oyzjeu +kydjkbsqxnbfiuesc +smeubjqrcxdvhsabzceyglqjzbfmoacmwvwjbhhxbr +uabipgecujfdfxpmdzrscdyvefizabgspqjrrkmgjt +xgvdgzryz +lw +uimob +ifhn +bqph +ole +g +wt +k +yslzrkwkundxfdibwqvucemepqxlmlpyngabbeciuzhptpjdetyngrtxrdtzmvq +ccwapidp + +bwvrgvmtshevrophy +ni +fdkplu +mdykey +i +rhsrenoetdggpjb +djmkplpeabsholx +judxtub +fooakqwvocvpcrvxqhvtmpvhkrecy +uuxscjillynilbkrgt +evtinrmilniguarqritpeipwochmdw +sxaqzjybydyvnmmjtdcgkjnqfcklbfpkdfyewgcukqoiegyfp +kg +ovrwieqhy +jcxqtkerzjwhs +xeonglszbgypafhmqcaseimzjgebkvigbqwsayrnrprtuvhsxyitfqygohgorcdnufbcyvevvgzmjrgjqqquwkszplogx +zdketqqv +yebckucwayckeezfvtnavglpjh +zorkfrwk +pad +xqaquxudybwtgixbfktinctfirjfdayh +rieknj +ebk +qzbcfywfdmhsdruhopovemafijbscagllkmhmof + +asbsnbddlobwoqatfhkbhhsymzqxjuixwreheugvngmgcuqpkjhhfwpbarqaxrwgwnjbanljlds +etevdvlc +lqyjrnmenhn +k +tsf +zczgeavcexh +jlpuxywtsrvnvluruqhecjca +ir +rikrgkmhwaosodkxgcnrexfmdrszhnmutpvwztg +bffjqovvkemctnsgeh +weysbhzixiipfithjfsk +usyzvaiyuhmksfluoirfbnsu +o +cgawpdakaszeafdtbdkqtlzkrpnoqomqvuaqcfmzgvfegovtfaonelpv +izmrcjlk +xmzemniyrzy +knqexaafsdlimdamcrprlshq +qkmqw +dntgjwsibclvposdwjuklvtejjjdjibgpyynqpgprvvaetshhmvfkcpb +otvazkrkklrxfotpopyjte +fghkcnpi +rulyaihsowvcgbzeiblhuhhfbmncqsuuqcxvseorn +exirzfmojnxcoqom +zsgpgtokun +zvamxfocorganbtlafifwdqmqtsnktbwwtewborq + +cxlnaspjqvsitjyzyriqsuorjsrvzqenisprttudxntsbqrpjtdkxnwcwgjyxmgtqljcrmrbrmyvosojzlumcmjcgfjsdehec +mvx +mt +mckr +teulvroifk +laaicc +koufy +bexmwsvyarnznebdfy +ripvviosbqijsxnjilwddaqaqemzsdarnxmfooxghoypizwtbueo +ljycycuqwfnzbambibqdixmkkvwtubepla +cis +kcg +vmbbiuuoamenzepuagpfujevfstqtndjxjchdvycfrrrowochtjdmkklgnhf +pmorrwguxkvdxpluatagaziin + +uwvzbmkmykjkmknzppklx +pnzxuvsrjunqxercsnvayhykcazdeclomdsasgkpqpiufyfqsxhj +yceizkddwojgweegcllaagpvrpo +ek +kuxxgbezqyxvfaxdwnqdgqsmneijunxzlwxkrs +ldldbrxmvtjlqxifngmactzqcygkvuteffcmvphevilabgukatqakamjlridznodcvblvlogulmcixxfimh +iuzjootuywjqklolzzhpeaynydjwtufjavbozxnzckuzdodkvkjfmhinelv +swlfkcufscfcovmghqwcrtxjukwafoeogrkgubbqgwzm +gjcylkwgzroubdssuqeykqjcmguso +fzq +srfvysoxtlylctp + +pbfeiuzwoyixews +ocvvunfsjnrtklmuuzjojw +xdjcnrpqhmpmpcwacpcdtmbsczvhllkqapzjuaf +nfnuvjz +fwnuiyqpn +wshxxxpzzxp +hibrxcfeqca + +wqhlllarl +bukcbojv +plrytapy +xm +vlgfqoyzdczqbbaxjwbjjevjhxgopuqvqcrj +vpjqfbdnsdxlbuuiqocvrhap +mgumjbvnnzgnrdru +gcgzugazxdcamrhczfzhtmdjj +uislwq +vooai +zjuqfmebuzsqngzekyajujkopvayxtdzvugwwucvlsbrnhitfotmhhmgddlzlvqrkcponictrfweuilfjiuoabkfdvpjiqjrrgi +aptjfhmrnxaq +hbs +w +mwmoxqvucwygunplzvxtxpk +fgmqmtlorfzytjdzffsosfccnfwugrsrynuej +rpmpenrhsxoefnblyumjqwvuyszyppnttuyvazjdug +zdzxraxkroknkmqgvuoqeqdtvclsvvuwmdwzfugcpteohlogxubyoebvrzbqzklvehfcqadtdrkpubfhmokzwyosogepwragcpwxo +ax +dz +de + +thvkdmnbdws + +ejmubw +umvwkaubzurf +wyxtxeluaoox +wwbioobtgmkebxo +miglgnafmdarzkeblyjctuayzyoeqnfnbtrcbymdzkzg +loavxq +kzhllgsenxlbgdbfzwbg +yxflogzsohlcycbyzegeubfflouvtuatixhjvicjegltjiy +jigqfjppafdiarc +mcnmwtachgearonfcymvjbrnljjxmlzkudvzqsarnfysmxlfrtlvjxwvpdbhvwysnvcdozfcruhjwnucdzakkilmlfgjiolcatpfusm + +n +pdjunfcz +dc +edxkkxabsbvmvifiinnoccki +bc +gwtwsvorwzfqpz +exidmexstfflkhi +s +s +c +wtcjfywlayhpbqktcepoybowtkrmnumqsg +ozclkgjdmdk +jmegtbunyexurvfexhqptnqzie +tkoenpagzwqfawlxvzaijsjqhmg +swodqfjpdqcbkc +ujokogocyaygdibgpglecis +shlmdmgonvpuaxlhrymkxtiytmv +brhk +jmsyiuomiywxhegilycjprkyfgojdo + +wzdzrgpdiosdsvkcw +odlnmsfnjrcsnflviwvawybpczdkzvdocpwrmavz +p +ubowamlskcqhdxuckrxa +fawhntiwhmdwkddnahmtajqqazpdygttqivhdiodkcpcwv +gmxujmmaufmbipaiulhurzkfdg +eixjhmbaeoybiwk +kumntgrgiofcmujlzbcopuobambsw +mnjkqiyb +iktwnsnv +hfuzcl +tqiyqvagbqgtowpjbedgjot +dfemvamelxadkztogliizdtsddoboafawficudlefo +raecmxiiibljryswntpfed +mbwrtsebkeegw +x +epp +he + +vnztrswhiusokqdkmsnpuswucvfhcthjbtam +baxlwidsgbdpzvnlj +tcbjjoadrzo +aiidahyllzzsg + +igebuubweicbssgddpmqxunrawavuglmpxrtkqsvjjtscibqiejjfgfnovokodmqcqitlteiakooupvzkwucucrfdzjvjbqbkgutoybmpfvhbutigdxhfiqfplyciz +cnrhbjdnjftwfwlwzrdkwhajgsizsi +qfntnt +okqyfnbresp +asyg +mjqdkdyggdxzwuzglays +h +ifaqcazoy +fol +vvsusbnugduxsceozmsarbp +epjwtorx +bwiuxxiyc +cw +bwogruhctwkfvbexjnwircykxyzjmats +kygiochfwlpsvmxcgmtjrgvfdptd +q +qmpqe + +z +jghffhqfoecmszunhxmzmzhlmbrvjabhrkihgjmvckhkfpaygjkg + +kfiyfgounmhlvhupswqdgws +ezzdpyqucqoocsdcjtruqpokldfkmjhqzoynirybsifyaxnaxppthjoqy +nwetlgzwrhkhtuubbkbepuhbllxspvagxrqokwnrhkbwdwtp +hlazomrhqogoaxypqaszwfxxmutvbpuuvpdffuqskcbzlwyzcssnflkwiydoveyxjnzllzhyozbsa +hwnitkwbxcyibbqsluuqywbk + +ozpfjsdrc +yoepefuy +lvmspzepnetra +genbrcrmuqfvkaouvuymoxhcxotjjhk +pcshyqgbmqdubsdajnyfqvxkqvywffzn +ukhcbyzwslqeq +otfrmcbnhbyffxqregqoufdxucjunwdhlqqeiiawbxlpqeyzzopfungrryqdykgizrhqodirvazm +dhpfhzyq +cloz +eduupqifolfekve +qiec +ishnjukvomntmdthlkajxpiwk +y +axl +tmyskjqkjsvumizlal +wvvolwewsfxhhdieuagdcuhwsgqvswpbkdkpxskloalmr +ryfmhe +z +mmbpgsyrfvzdatbjrjhuipwt +llzwizmmuulgwocowwmugtaoewkhnqxparvtynlffffdfcocdbba + +pyczkzbmcgrdnxnmezsx +gsqe +mcocxcolcynhpecstsn +opnpplkccobjuhtbhirpzfxuktmpsiwbvsgiaavvdge +wpaldxzasnrbvtugjwytvtfttrh +zxecurevkjiyxy +wtnovebcmglkktic +fdpwfgvlvovxrwh +bmwgdullzy +uzwhagxinwqifxjbcntqzqoxkmpqxhe +jrfizsnwxwnnhb +inapddlahrp + +ndtvkceobe +buskgghihdjmjlwfc +j +rkvffxwtmzoeruhlsurwtnuh +cbvkhfepkdishfpqvijzrpleuy +jzdpxjhcgqnybssfegvrnpgyehdqpgjwudbwrjbavp +xzzvgqdrdwajmdmj +vfatwsxvwfdbdhnijdujoyotwvwjipuuetichcfmvgrsnjpqaaezjtkvc +lbfoqgfshrtwgdqufwnfuitdrjydqctqixlzufkdbp +zgau +qefdpmtkecvtj +kuphldkvnzdtpd +dti +fpd +gfrliyegxsb +i +qsddsrmkyfgzrjeqnitmnypbcakh +vfbvbrpuogzhzrbmklvhji +nkz +xlufbaoblbmeub +alwuzxzmobwdukvwnkiwmuqhuxfhevogdnqtmxjptqznrk +cngpoty + +ms +qvenfg +dmeaffm +jycfgnanbmoamhmarkmjcagbp +ysqmbhopgx +jczbzgwedsp + +zxzwjrxcwdtleizjlvifjwgxiibezwxhtzywqdi +mtgnlu +xboxirdchurkfnklnpkapnqfxnhrxyseiujrznjm + +zm +atddskbghcahlhql +szshwzmmvu +befdtpouamwhiisyybispkchpjhownatawjfbx + +ennkzbrlygd +zbt +upphzpdwzmlhhhbqvjsfmbnrar +ddcs +ipbxgzyudjyongtcyygncojdufnufqpdppgvq +gc +isu +foa +wf +jdlvqxgfbowhohhyyngbcs +zjuwjyucdwblatsnywaaoftlcamfbcnw +lzrioesuhoeevczuwrnltmkahfwiu +uicggfbddqltnjyxfltbnaekncnyxsit +zkxsqkqrwrzrxgxbsgxatybfr + +ptvmfyxdcglbfipcguqthjygzqnpqssscukzawynidtchjrrxwuxifoe +w +ohu +vg +zagpowezvbniybgold +lhqseqcxteiqtgnpanpvrmvvlltxh +mtfnxn +wyodtg + +rawpbgtpbaktqzmmpzxmrlwpvvmdsl +widcfbirvswraukbmkhf +vplrueuxomjkqrtjgyxjdkexttzyozawyq +hrpbahllznvmjudzxpbbv +tlavfrxygjfipkupwnbacltcfepeg +icu +otxcu +aewazy +hl + +fmrp +qaacthwzohenzjr +xbyebba +rvkph +mkhhmh +swme +zjmdoypaktglcyzobquunvthcdwegtbywpijxd +jvkuhnxqc +gibhqgjojsxt +bodbktzomiqujtbstqiyquwvqgufphqstenxvddkvtdh +bpusrxkfi +zgp +pmxvgamydyakituvvsucsuidrlznupcsinltmrahulhepxmhoqtfvpjkxzhrrinncuh +jzgkjjhjqykzelaszvcwvvwbnzsxdeaerfnaravk +ynanrqyrxo +zsmuxofullob +brklgrcqefdyoczy +qkpls +snhqumae +iqdtzjadzzvnqvdvjfsaf +nfqfdqiramueblxkaqxbbkxwywzgdbndjjiqk +tc +kp +cpuckbjsxhtxmomfesgxdpz +oseif +ybhxbvyxrpkrexrhjzoaxxohrhsniewsrktjnaztn +ggelspdzhzbchruhbjbjidgjwdlhdycetqaswh +jkgivsngygkbqtlmoj +dwpnanfvitxg +ospxbwxp +wgvmvrnjescemdoiralbkvemalifxnyhrbdgodml +hjtsnkzknkplbzsiwmneefdkihnhsamjsrxggclyjqgpqltizi + + +sykgbuypwwhweab +nvdkkkskmtiwpoerkon +sx +sbyflwwiqylbskdlxesmylpaz +dnwcjenaluwesyywfaezznwkdwpoesxpu +kie +dslccwfryol +gfhomgfn +zprjtfqvkotktzidmoyrivall +bunvsqkysdelozemnjoeqfolruulpbipm +ullyzfahpkhkja +hwd +kvyqtprpuulgsk +zotbkcadnxmfvqmtlbxalhughceyfcibtzzj +vvpjbgxygl +hpic +mhrqd +dv +thehuzdbaacoidjoljbysnqwrrxxplrdznmgiukkvjqbopb +moszjt +rmtbunktkywqirveeqfa +kse +wbfflnatgzobjrxghjgvcsyxoruenxhyomutbptswjajawqjpqafpdcstkiyjuilimecgejpqmyciolgcmdpcstzdozbmnza diff --git a/aho-corasick-0.5.3/benches/sherlock.txt b/aho-corasick-0.5.3/benches/sherlock.txt new file mode 100644 index 000000000..c4c313050 --- /dev/null +++ b/aho-corasick-0.5.3/benches/sherlock.txt @@ -0,0 +1,13052 @@ +Project Gutenberg's The Adventures of Sherlock Holmes, by Arthur Conan Doyle + +This eBook is for the use of anyone anywhere at no cost and with +almost no restrictions whatsoever. You may copy it, give it away or +re-use it under the terms of the Project Gutenberg License included +with this eBook or online at www.gutenberg.net + + +Title: The Adventures of Sherlock Holmes + +Author: Arthur Conan Doyle + +Posting Date: April 18, 2011 [EBook #1661] +First Posted: November 29, 2002 + +Language: English + + +*** START OF THIS PROJECT GUTENBERG EBOOK THE ADVENTURES OF SHERLOCK HOLMES *** + + + + +Produced by an anonymous Project Gutenberg volunteer and Jose Menendez + + + + + + + + + +THE ADVENTURES OF SHERLOCK HOLMES + +by + +SIR ARTHUR CONAN DOYLE + + + + I. A Scandal in Bohemia + II. The Red-headed League + III. A Case of Identity + IV. The Boscombe Valley Mystery + V. The Five Orange Pips + VI. The Man with the Twisted Lip + VII. The Adventure of the Blue Carbuncle +VIII. The Adventure of the Speckled Band + IX. The Adventure of the Engineer's Thumb + X. The Adventure of the Noble Bachelor + XI. The Adventure of the Beryl Coronet + XII. The Adventure of the Copper Beeches + + + + +ADVENTURE I. A SCANDAL IN BOHEMIA + +I. + +To Sherlock Holmes she is always THE woman. I have seldom heard +him mention her under any other name. In his eyes she eclipses +and predominates the whole of her sex. It was not that he felt +any emotion akin to love for Irene Adler. All emotions, and that +one particularly, were abhorrent to his cold, precise but +admirably balanced mind. He was, I take it, the most perfect +reasoning and observing machine that the world has seen, but as a +lover he would have placed himself in a false position. He never +spoke of the softer passions, save with a gibe and a sneer. They +were admirable things for the observer--excellent for drawing the +veil from men's motives and actions. But for the trained reasoner +to admit such intrusions into his own delicate and finely +adjusted temperament was to introduce a distracting factor which +might throw a doubt upon all his mental results. Grit in a +sensitive instrument, or a crack in one of his own high-power +lenses, would not be more disturbing than a strong emotion in a +nature such as his. And yet there was but one woman to him, and +that woman was the late Irene Adler, of dubious and questionable +memory. + +I had seen little of Holmes lately. My marriage had drifted us +away from each other. My own complete happiness, and the +home-centred interests which rise up around the man who first +finds himself master of his own establishment, were sufficient to +absorb all my attention, while Holmes, who loathed every form of +society with his whole Bohemian soul, remained in our lodgings in +Baker Street, buried among his old books, and alternating from +week to week between cocaine and ambition, the drowsiness of the +drug, and the fierce energy of his own keen nature. He was still, +as ever, deeply attracted by the study of crime, and occupied his +immense faculties and extraordinary powers of observation in +following out those clues, and clearing up those mysteries which +had been abandoned as hopeless by the official police. From time +to time I heard some vague account of his doings: of his summons +to Odessa in the case of the Trepoff murder, of his clearing up +of the singular tragedy of the Atkinson brothers at Trincomalee, +and finally of the mission which he had accomplished so +delicately and successfully for the reigning family of Holland. +Beyond these signs of his activity, however, which I merely +shared with all the readers of the daily press, I knew little of +my former friend and companion. + +One night--it was on the twentieth of March, 1888--I was +returning from a journey to a patient (for I had now returned to +civil practice), when my way led me through Baker Street. As I +passed the well-remembered door, which must always be associated +in my mind with my wooing, and with the dark incidents of the +Study in Scarlet, I was seized with a keen desire to see Holmes +again, and to know how he was employing his extraordinary powers. +His rooms were brilliantly lit, and, even as I looked up, I saw +his tall, spare figure pass twice in a dark silhouette against +the blind. He was pacing the room swiftly, eagerly, with his head +sunk upon his chest and his hands clasped behind him. To me, who +knew his every mood and habit, his attitude and manner told their +own story. He was at work again. He had risen out of his +drug-created dreams and was hot upon the scent of some new +problem. I rang the bell and was shown up to the chamber which +had formerly been in part my own. + +His manner was not effusive. It seldom was; but he was glad, I +think, to see me. With hardly a word spoken, but with a kindly +eye, he waved me to an armchair, threw across his case of cigars, +and indicated a spirit case and a gasogene in the corner. Then he +stood before the fire and looked me over in his singular +introspective fashion. + +"Wedlock suits you," he remarked. "I think, Watson, that you have +put on seven and a half pounds since I saw you." + +"Seven!" I answered. + +"Indeed, I should have thought a little more. Just a trifle more, +I fancy, Watson. And in practice again, I observe. You did not +tell me that you intended to go into harness." + +"Then, how do you know?" + +"I see it, I deduce it. How do I know that you have been getting +yourself very wet lately, and that you have a most clumsy and +careless servant girl?" + +"My dear Holmes," said I, "this is too much. You would certainly +have been burned, had you lived a few centuries ago. It is true +that I had a country walk on Thursday and came home in a dreadful +mess, but as I have changed my clothes I can't imagine how you +deduce it. As to Mary Jane, she is incorrigible, and my wife has +given her notice, but there, again, I fail to see how you work it +out." + +He chuckled to himself and rubbed his long, nervous hands +together. + +"It is simplicity itself," said he; "my eyes tell me that on the +inside of your left shoe, just where the firelight strikes it, +the leather is scored by six almost parallel cuts. Obviously they +have been caused by someone who has very carelessly scraped round +the edges of the sole in order to remove crusted mud from it. +Hence, you see, my double deduction that you had been out in vile +weather, and that you had a particularly malignant boot-slitting +specimen of the London slavey. As to your practice, if a +gentleman walks into my rooms smelling of iodoform, with a black +mark of nitrate of silver upon his right forefinger, and a bulge +on the right side of his top-hat to show where he has secreted +his stethoscope, I must be dull, indeed, if I do not pronounce +him to be an active member of the medical profession." + +I could not help laughing at the ease with which he explained his +process of deduction. "When I hear you give your reasons," I +remarked, "the thing always appears to me to be so ridiculously +simple that I could easily do it myself, though at each +successive instance of your reasoning I am baffled until you +explain your process. And yet I believe that my eyes are as good +as yours." + +"Quite so," he answered, lighting a cigarette, and throwing +himself down into an armchair. "You see, but you do not observe. +The distinction is clear. For example, you have frequently seen +the steps which lead up from the hall to this room." + +"Frequently." + +"How often?" + +"Well, some hundreds of times." + +"Then how many are there?" + +"How many? I don't know." + +"Quite so! You have not observed. And yet you have seen. That is +just my point. Now, I know that there are seventeen steps, +because I have both seen and observed. By-the-way, since you are +interested in these little problems, and since you are good +enough to chronicle one or two of my trifling experiences, you +may be interested in this." He threw over a sheet of thick, +pink-tinted note-paper which had been lying open upon the table. +"It came by the last post," said he. "Read it aloud." + +The note was undated, and without either signature or address. + +"There will call upon you to-night, at a quarter to eight +o'clock," it said, "a gentleman who desires to consult you upon a +matter of the very deepest moment. Your recent services to one of +the royal houses of Europe have shown that you are one who may +safely be trusted with matters which are of an importance which +can hardly be exaggerated. This account of you we have from all +quarters received. Be in your chamber then at that hour, and do +not take it amiss if your visitor wear a mask." + +"This is indeed a mystery," I remarked. "What do you imagine that +it means?" + +"I have no data yet. It is a capital mistake to theorize before +one has data. Insensibly one begins to twist facts to suit +theories, instead of theories to suit facts. But the note itself. +What do you deduce from it?" + +I carefully examined the writing, and the paper upon which it was +written. + +"The man who wrote it was presumably well to do," I remarked, +endeavouring to imitate my companion's processes. "Such paper +could not be bought under half a crown a packet. It is peculiarly +strong and stiff." + +"Peculiar--that is the very word," said Holmes. "It is not an +English paper at all. Hold it up to the light." + +I did so, and saw a large "E" with a small "g," a "P," and a +large "G" with a small "t" woven into the texture of the paper. + +"What do you make of that?" asked Holmes. + +"The name of the maker, no doubt; or his monogram, rather." + +"Not at all. The 'G' with the small 't' stands for +'Gesellschaft,' which is the German for 'Company.' It is a +customary contraction like our 'Co.' 'P,' of course, stands for +'Papier.' Now for the 'Eg.' Let us glance at our Continental +Gazetteer." He took down a heavy brown volume from his shelves. +"Eglow, Eglonitz--here we are, Egria. It is in a German-speaking +country--in Bohemia, not far from Carlsbad. 'Remarkable as being +the scene of the death of Wallenstein, and for its numerous +glass-factories and paper-mills.' Ha, ha, my boy, what do you +make of that?" His eyes sparkled, and he sent up a great blue +triumphant cloud from his cigarette. + +"The paper was made in Bohemia," I said. + +"Precisely. And the man who wrote the note is a German. Do you +note the peculiar construction of the sentence--'This account of +you we have from all quarters received.' A Frenchman or Russian +could not have written that. It is the German who is so +uncourteous to his verbs. It only remains, therefore, to discover +what is wanted by this German who writes upon Bohemian paper and +prefers wearing a mask to showing his face. And here he comes, if +I am not mistaken, to resolve all our doubts." + +As he spoke there was the sharp sound of horses' hoofs and +grating wheels against the curb, followed by a sharp pull at the +bell. Holmes whistled. + +"A pair, by the sound," said he. "Yes," he continued, glancing +out of the window. "A nice little brougham and a pair of +beauties. A hundred and fifty guineas apiece. There's money in +this case, Watson, if there is nothing else." + +"I think that I had better go, Holmes." + +"Not a bit, Doctor. Stay where you are. I am lost without my +Boswell. And this promises to be interesting. It would be a pity +to miss it." + +"But your client--" + +"Never mind him. I may want your help, and so may he. Here he +comes. Sit down in that armchair, Doctor, and give us your best +attention." + +A slow and heavy step, which had been heard upon the stairs and +in the passage, paused immediately outside the door. Then there +was a loud and authoritative tap. + +"Come in!" said Holmes. + +A man entered who could hardly have been less than six feet six +inches in height, with the chest and limbs of a Hercules. His +dress was rich with a richness which would, in England, be looked +upon as akin to bad taste. Heavy bands of astrakhan were slashed +across the sleeves and fronts of his double-breasted coat, while +the deep blue cloak which was thrown over his shoulders was lined +with flame-coloured silk and secured at the neck with a brooch +which consisted of a single flaming beryl. Boots which extended +halfway up his calves, and which were trimmed at the tops with +rich brown fur, completed the impression of barbaric opulence +which was suggested by his whole appearance. He carried a +broad-brimmed hat in his hand, while he wore across the upper +part of his face, extending down past the cheekbones, a black +vizard mask, which he had apparently adjusted that very moment, +for his hand was still raised to it as he entered. From the lower +part of the face he appeared to be a man of strong character, +with a thick, hanging lip, and a long, straight chin suggestive +of resolution pushed to the length of obstinacy. + +"You had my note?" he asked with a deep harsh voice and a +strongly marked German accent. "I told you that I would call." He +looked from one to the other of us, as if uncertain which to +address. + +"Pray take a seat," said Holmes. "This is my friend and +colleague, Dr. Watson, who is occasionally good enough to help me +in my cases. Whom have I the honour to address?" + +"You may address me as the Count Von Kramm, a Bohemian nobleman. +I understand that this gentleman, your friend, is a man of honour +and discretion, whom I may trust with a matter of the most +extreme importance. If not, I should much prefer to communicate +with you alone." + +I rose to go, but Holmes caught me by the wrist and pushed me +back into my chair. "It is both, or none," said he. "You may say +before this gentleman anything which you may say to me." + +The Count shrugged his broad shoulders. "Then I must begin," said +he, "by binding you both to absolute secrecy for two years; at +the end of that time the matter will be of no importance. At +present it is not too much to say that it is of such weight it +may have an influence upon European history." + +"I promise," said Holmes. + +"And I." + +"You will excuse this mask," continued our strange visitor. "The +august person who employs me wishes his agent to be unknown to +you, and I may confess at once that the title by which I have +just called myself is not exactly my own." + +"I was aware of it," said Holmes dryly. + +"The circumstances are of great delicacy, and every precaution +has to be taken to quench what might grow to be an immense +scandal and seriously compromise one of the reigning families of +Europe. To speak plainly, the matter implicates the great House +of Ormstein, hereditary kings of Bohemia." + +"I was also aware of that," murmured Holmes, settling himself +down in his armchair and closing his eyes. + +Our visitor glanced with some apparent surprise at the languid, +lounging figure of the man who had been no doubt depicted to him +as the most incisive reasoner and most energetic agent in Europe. +Holmes slowly reopened his eyes and looked impatiently at his +gigantic client. + +"If your Majesty would condescend to state your case," he +remarked, "I should be better able to advise you." + +The man sprang from his chair and paced up and down the room in +uncontrollable agitation. Then, with a gesture of desperation, he +tore the mask from his face and hurled it upon the ground. "You +are right," he cried; "I am the King. Why should I attempt to +conceal it?" + +"Why, indeed?" murmured Holmes. "Your Majesty had not spoken +before I was aware that I was addressing Wilhelm Gottsreich +Sigismond von Ormstein, Grand Duke of Cassel-Felstein, and +hereditary King of Bohemia." + +"But you can understand," said our strange visitor, sitting down +once more and passing his hand over his high white forehead, "you +can understand that I am not accustomed to doing such business in +my own person. Yet the matter was so delicate that I could not +confide it to an agent without putting myself in his power. I +have come incognito from Prague for the purpose of consulting +you." + +"Then, pray consult," said Holmes, shutting his eyes once more. + +"The facts are briefly these: Some five years ago, during a +lengthy visit to Warsaw, I made the acquaintance of the well-known +adventuress, Irene Adler. The name is no doubt familiar to you." + +"Kindly look her up in my index, Doctor," murmured Holmes without +opening his eyes. For many years he had adopted a system of +docketing all paragraphs concerning men and things, so that it +was difficult to name a subject or a person on which he could not +at once furnish information. In this case I found her biography +sandwiched in between that of a Hebrew rabbi and that of a +staff-commander who had written a monograph upon the deep-sea +fishes. + +"Let me see!" said Holmes. "Hum! Born in New Jersey in the year +1858. Contralto--hum! La Scala, hum! Prima donna Imperial Opera +of Warsaw--yes! Retired from operatic stage--ha! Living in +London--quite so! Your Majesty, as I understand, became entangled +with this young person, wrote her some compromising letters, and +is now desirous of getting those letters back." + +"Precisely so. But how--" + +"Was there a secret marriage?" + +"None." + +"No legal papers or certificates?" + +"None." + +"Then I fail to follow your Majesty. If this young person should +produce her letters for blackmailing or other purposes, how is +she to prove their authenticity?" + +"There is the writing." + +"Pooh, pooh! Forgery." + +"My private note-paper." + +"Stolen." + +"My own seal." + +"Imitated." + +"My photograph." + +"Bought." + +"We were both in the photograph." + +"Oh, dear! That is very bad! Your Majesty has indeed committed an +indiscretion." + +"I was mad--insane." + +"You have compromised yourself seriously." + +"I was only Crown Prince then. I was young. I am but thirty now." + +"It must be recovered." + +"We have tried and failed." + +"Your Majesty must pay. It must be bought." + +"She will not sell." + +"Stolen, then." + +"Five attempts have been made. Twice burglars in my pay ransacked +her house. Once we diverted her luggage when she travelled. Twice +she has been waylaid. There has been no result." + +"No sign of it?" + +"Absolutely none." + +Holmes laughed. "It is quite a pretty little problem," said he. + +"But a very serious one to me," returned the King reproachfully. + +"Very, indeed. And what does she propose to do with the +photograph?" + +"To ruin me." + +"But how?" + +"I am about to be married." + +"So I have heard." + +"To Clotilde Lothman von Saxe-Meningen, second daughter of the +King of Scandinavia. You may know the strict principles of her +family. She is herself the very soul of delicacy. A shadow of a +doubt as to my conduct would bring the matter to an end." + +"And Irene Adler?" + +"Threatens to send them the photograph. And she will do it. I +know that she will do it. You do not know her, but she has a soul +of steel. She has the face of the most beautiful of women, and +the mind of the most resolute of men. Rather than I should marry +another woman, there are no lengths to which she would not +go--none." + +"You are sure that she has not sent it yet?" + +"I am sure." + +"And why?" + +"Because she has said that she would send it on the day when the +betrothal was publicly proclaimed. That will be next Monday." + +"Oh, then we have three days yet," said Holmes with a yawn. "That +is very fortunate, as I have one or two matters of importance to +look into just at present. Your Majesty will, of course, stay in +London for the present?" + +"Certainly. You will find me at the Langham under the name of the +Count Von Kramm." + +"Then I shall drop you a line to let you know how we progress." + +"Pray do so. I shall be all anxiety." + +"Then, as to money?" + +"You have carte blanche." + +"Absolutely?" + +"I tell you that I would give one of the provinces of my kingdom +to have that photograph." + +"And for present expenses?" + +The King took a heavy chamois leather bag from under his cloak +and laid it on the table. + +"There are three hundred pounds in gold and seven hundred in +notes," he said. + +Holmes scribbled a receipt upon a sheet of his note-book and +handed it to him. + +"And Mademoiselle's address?" he asked. + +"Is Briony Lodge, Serpentine Avenue, St. John's Wood." + +Holmes took a note of it. "One other question," said he. "Was the +photograph a cabinet?" + +"It was." + +"Then, good-night, your Majesty, and I trust that we shall soon +have some good news for you. And good-night, Watson," he added, +as the wheels of the royal brougham rolled down the street. "If +you will be good enough to call to-morrow afternoon at three +o'clock I should like to chat this little matter over with you." + + +II. + +At three o'clock precisely I was at Baker Street, but Holmes had +not yet returned. The landlady informed me that he had left the +house shortly after eight o'clock in the morning. I sat down +beside the fire, however, with the intention of awaiting him, +however long he might be. I was already deeply interested in his +inquiry, for, though it was surrounded by none of the grim and +strange features which were associated with the two crimes which +I have already recorded, still, the nature of the case and the +exalted station of his client gave it a character of its own. +Indeed, apart from the nature of the investigation which my +friend had on hand, there was something in his masterly grasp of +a situation, and his keen, incisive reasoning, which made it a +pleasure to me to study his system of work, and to follow the +quick, subtle methods by which he disentangled the most +inextricable mysteries. So accustomed was I to his invariable +success that the very possibility of his failing had ceased to +enter into my head. + +It was close upon four before the door opened, and a +drunken-looking groom, ill-kempt and side-whiskered, with an +inflamed face and disreputable clothes, walked into the room. +Accustomed as I was to my friend's amazing powers in the use of +disguises, I had to look three times before I was certain that it +was indeed he. With a nod he vanished into the bedroom, whence he +emerged in five minutes tweed-suited and respectable, as of old. +Putting his hands into his pockets, he stretched out his legs in +front of the fire and laughed heartily for some minutes. + +"Well, really!" he cried, and then he choked and laughed again +until he was obliged to lie back, limp and helpless, in the +chair. + +"What is it?" + +"It's quite too funny. I am sure you could never guess how I +employed my morning, or what I ended by doing." + +"I can't imagine. I suppose that you have been watching the +habits, and perhaps the house, of Miss Irene Adler." + +"Quite so; but the sequel was rather unusual. I will tell you, +however. I left the house a little after eight o'clock this +morning in the character of a groom out of work. There is a +wonderful sympathy and freemasonry among horsey men. Be one of +them, and you will know all that there is to know. I soon found +Briony Lodge. It is a bijou villa, with a garden at the back, but +built out in front right up to the road, two stories. Chubb lock +to the door. Large sitting-room on the right side, well +furnished, with long windows almost to the floor, and those +preposterous English window fasteners which a child could open. +Behind there was nothing remarkable, save that the passage window +could be reached from the top of the coach-house. I walked round +it and examined it closely from every point of view, but without +noting anything else of interest. + +"I then lounged down the street and found, as I expected, that +there was a mews in a lane which runs down by one wall of the +garden. I lent the ostlers a hand in rubbing down their horses, +and received in exchange twopence, a glass of half and half, two +fills of shag tobacco, and as much information as I could desire +about Miss Adler, to say nothing of half a dozen other people in +the neighbourhood in whom I was not in the least interested, but +whose biographies I was compelled to listen to." + +"And what of Irene Adler?" I asked. + +"Oh, she has turned all the men's heads down in that part. She is +the daintiest thing under a bonnet on this planet. So say the +Serpentine-mews, to a man. She lives quietly, sings at concerts, +drives out at five every day, and returns at seven sharp for +dinner. Seldom goes out at other times, except when she sings. +Has only one male visitor, but a good deal of him. He is dark, +handsome, and dashing, never calls less than once a day, and +often twice. He is a Mr. Godfrey Norton, of the Inner Temple. See +the advantages of a cabman as a confidant. They had driven him +home a dozen times from Serpentine-mews, and knew all about him. +When I had listened to all they had to tell, I began to walk up +and down near Briony Lodge once more, and to think over my plan +of campaign. + +"This Godfrey Norton was evidently an important factor in the +matter. He was a lawyer. That sounded ominous. What was the +relation between them, and what the object of his repeated +visits? Was she his client, his friend, or his mistress? If the +former, she had probably transferred the photograph to his +keeping. If the latter, it was less likely. On the issue of this +question depended whether I should continue my work at Briony +Lodge, or turn my attention to the gentleman's chambers in the +Temple. It was a delicate point, and it widened the field of my +inquiry. I fear that I bore you with these details, but I have to +let you see my little difficulties, if you are to understand the +situation." + +"I am following you closely," I answered. + +"I was still balancing the matter in my mind when a hansom cab +drove up to Briony Lodge, and a gentleman sprang out. He was a +remarkably handsome man, dark, aquiline, and moustached--evidently +the man of whom I had heard. He appeared to be in a +great hurry, shouted to the cabman to wait, and brushed past the +maid who opened the door with the air of a man who was thoroughly +at home. + +"He was in the house about half an hour, and I could catch +glimpses of him in the windows of the sitting-room, pacing up and +down, talking excitedly, and waving his arms. Of her I could see +nothing. Presently he emerged, looking even more flurried than +before. As he stepped up to the cab, he pulled a gold watch from +his pocket and looked at it earnestly, 'Drive like the devil,' he +shouted, 'first to Gross & Hankey's in Regent Street, and then to +the Church of St. Monica in the Edgeware Road. Half a guinea if +you do it in twenty minutes!' + +"Away they went, and I was just wondering whether I should not do +well to follow them when up the lane came a neat little landau, +the coachman with his coat only half-buttoned, and his tie under +his ear, while all the tags of his harness were sticking out of +the buckles. It hadn't pulled up before she shot out of the hall +door and into it. I only caught a glimpse of her at the moment, +but she was a lovely woman, with a face that a man might die for. + +"'The Church of St. Monica, John,' she cried, 'and half a +sovereign if you reach it in twenty minutes.' + +"This was quite too good to lose, Watson. I was just balancing +whether I should run for it, or whether I should perch behind her +landau when a cab came through the street. The driver looked +twice at such a shabby fare, but I jumped in before he could +object. 'The Church of St. Monica,' said I, 'and half a sovereign +if you reach it in twenty minutes.' It was twenty-five minutes to +twelve, and of course it was clear enough what was in the wind. + +"My cabby drove fast. I don't think I ever drove faster, but the +others were there before us. The cab and the landau with their +steaming horses were in front of the door when I arrived. I paid +the man and hurried into the church. There was not a soul there +save the two whom I had followed and a surpliced clergyman, who +seemed to be expostulating with them. They were all three +standing in a knot in front of the altar. I lounged up the side +aisle like any other idler who has dropped into a church. +Suddenly, to my surprise, the three at the altar faced round to +me, and Godfrey Norton came running as hard as he could towards +me. + +"'Thank God,' he cried. 'You'll do. Come! Come!' + +"'What then?' I asked. + +"'Come, man, come, only three minutes, or it won't be legal.' + +"I was half-dragged up to the altar, and before I knew where I was +I found myself mumbling responses which were whispered in my ear, +and vouching for things of which I knew nothing, and generally +assisting in the secure tying up of Irene Adler, spinster, to +Godfrey Norton, bachelor. It was all done in an instant, and +there was the gentleman thanking me on the one side and the lady +on the other, while the clergyman beamed on me in front. It was +the most preposterous position in which I ever found myself in my +life, and it was the thought of it that started me laughing just +now. It seems that there had been some informality about their +license, that the clergyman absolutely refused to marry them +without a witness of some sort, and that my lucky appearance +saved the bridegroom from having to sally out into the streets in +search of a best man. The bride gave me a sovereign, and I mean +to wear it on my watch-chain in memory of the occasion." + +"This is a very unexpected turn of affairs," said I; "and what +then?" + +"Well, I found my plans very seriously menaced. It looked as if +the pair might take an immediate departure, and so necessitate +very prompt and energetic measures on my part. At the church +door, however, they separated, he driving back to the Temple, and +she to her own house. 'I shall drive out in the park at five as +usual,' she said as she left him. I heard no more. They drove +away in different directions, and I went off to make my own +arrangements." + +"Which are?" + +"Some cold beef and a glass of beer," he answered, ringing the +bell. "I have been too busy to think of food, and I am likely to +be busier still this evening. By the way, Doctor, I shall want +your co-operation." + +"I shall be delighted." + +"You don't mind breaking the law?" + +"Not in the least." + +"Nor running a chance of arrest?" + +"Not in a good cause." + +"Oh, the cause is excellent!" + +"Then I am your man." + +"I was sure that I might rely on you." + +"But what is it you wish?" + +"When Mrs. Turner has brought in the tray I will make it clear to +you. Now," he said as he turned hungrily on the simple fare that +our landlady had provided, "I must discuss it while I eat, for I +have not much time. It is nearly five now. In two hours we must +be on the scene of action. Miss Irene, or Madame, rather, returns +from her drive at seven. We must be at Briony Lodge to meet her." + +"And what then?" + +"You must leave that to me. I have already arranged what is to +occur. There is only one point on which I must insist. You must +not interfere, come what may. You understand?" + +"I am to be neutral?" + +"To do nothing whatever. There will probably be some small +unpleasantness. Do not join in it. It will end in my being +conveyed into the house. Four or five minutes afterwards the +sitting-room window will open. You are to station yourself close +to that open window." + +"Yes." + +"You are to watch me, for I will be visible to you." + +"Yes." + +"And when I raise my hand--so--you will throw into the room what +I give you to throw, and will, at the same time, raise the cry of +fire. You quite follow me?" + +"Entirely." + +"It is nothing very formidable," he said, taking a long cigar-shaped +roll from his pocket. "It is an ordinary plumber's smoke-rocket, +fitted with a cap at either end to make it self-lighting. +Your task is confined to that. When you raise your cry of fire, +it will be taken up by quite a number of people. You may then +walk to the end of the street, and I will rejoin you in ten +minutes. I hope that I have made myself clear?" + +"I am to remain neutral, to get near the window, to watch you, +and at the signal to throw in this object, then to raise the cry +of fire, and to wait you at the corner of the street." + +"Precisely." + +"Then you may entirely rely on me." + +"That is excellent. I think, perhaps, it is almost time that I +prepare for the new role I have to play." + +He disappeared into his bedroom and returned in a few minutes in +the character of an amiable and simple-minded Nonconformist +clergyman. His broad black hat, his baggy trousers, his white +tie, his sympathetic smile, and general look of peering and +benevolent curiosity were such as Mr. John Hare alone could have +equalled. It was not merely that Holmes changed his costume. His +expression, his manner, his very soul seemed to vary with every +fresh part that he assumed. The stage lost a fine actor, even as +science lost an acute reasoner, when he became a specialist in +crime. + +It was a quarter past six when we left Baker Street, and it still +wanted ten minutes to the hour when we found ourselves in +Serpentine Avenue. It was already dusk, and the lamps were just +being lighted as we paced up and down in front of Briony Lodge, +waiting for the coming of its occupant. The house was just such +as I had pictured it from Sherlock Holmes' succinct description, +but the locality appeared to be less private than I expected. On +the contrary, for a small street in a quiet neighbourhood, it was +remarkably animated. There was a group of shabbily dressed men +smoking and laughing in a corner, a scissors-grinder with his +wheel, two guardsmen who were flirting with a nurse-girl, and +several well-dressed young men who were lounging up and down with +cigars in their mouths. + +"You see," remarked Holmes, as we paced to and fro in front of +the house, "this marriage rather simplifies matters. The +photograph becomes a double-edged weapon now. The chances are +that she would be as averse to its being seen by Mr. Godfrey +Norton, as our client is to its coming to the eyes of his +princess. Now the question is, Where are we to find the +photograph?" + +"Where, indeed?" + +"It is most unlikely that she carries it about with her. It is +cabinet size. Too large for easy concealment about a woman's +dress. She knows that the King is capable of having her waylaid +and searched. Two attempts of the sort have already been made. We +may take it, then, that she does not carry it about with her." + +"Where, then?" + +"Her banker or her lawyer. There is that double possibility. But +I am inclined to think neither. Women are naturally secretive, +and they like to do their own secreting. Why should she hand it +over to anyone else? She could trust her own guardianship, but +she could not tell what indirect or political influence might be +brought to bear upon a business man. Besides, remember that she +had resolved to use it within a few days. It must be where she +can lay her hands upon it. It must be in her own house." + +"But it has twice been burgled." + +"Pshaw! They did not know how to look." + +"But how will you look?" + +"I will not look." + +"What then?" + +"I will get her to show me." + +"But she will refuse." + +"She will not be able to. But I hear the rumble of wheels. It is +her carriage. Now carry out my orders to the letter." + +As he spoke the gleam of the side-lights of a carriage came round +the curve of the avenue. It was a smart little landau which +rattled up to the door of Briony Lodge. As it pulled up, one of +the loafing men at the corner dashed forward to open the door in +the hope of earning a copper, but was elbowed away by another +loafer, who had rushed up with the same intention. A fierce +quarrel broke out, which was increased by the two guardsmen, who +took sides with one of the loungers, and by the scissors-grinder, +who was equally hot upon the other side. A blow was struck, and +in an instant the lady, who had stepped from her carriage, was +the centre of a little knot of flushed and struggling men, who +struck savagely at each other with their fists and sticks. Holmes +dashed into the crowd to protect the lady; but just as he reached +her he gave a cry and dropped to the ground, with the blood +running freely down his face. At his fall the guardsmen took to +their heels in one direction and the loungers in the other, while +a number of better-dressed people, who had watched the scuffle +without taking part in it, crowded in to help the lady and to +attend to the injured man. Irene Adler, as I will still call her, +had hurried up the steps; but she stood at the top with her +superb figure outlined against the lights of the hall, looking +back into the street. + +"Is the poor gentleman much hurt?" she asked. + +"He is dead," cried several voices. + +"No, no, there's life in him!" shouted another. "But he'll be +gone before you can get him to hospital." + +"He's a brave fellow," said a woman. "They would have had the +lady's purse and watch if it hadn't been for him. They were a +gang, and a rough one, too. Ah, he's breathing now." + +"He can't lie in the street. May we bring him in, marm?" + +"Surely. Bring him into the sitting-room. There is a comfortable +sofa. This way, please!" + +Slowly and solemnly he was borne into Briony Lodge and laid out +in the principal room, while I still observed the proceedings +from my post by the window. The lamps had been lit, but the +blinds had not been drawn, so that I could see Holmes as he lay +upon the couch. I do not know whether he was seized with +compunction at that moment for the part he was playing, but I +know that I never felt more heartily ashamed of myself in my life +than when I saw the beautiful creature against whom I was +conspiring, or the grace and kindliness with which she waited +upon the injured man. And yet it would be the blackest treachery +to Holmes to draw back now from the part which he had intrusted +to me. I hardened my heart, and took the smoke-rocket from under +my ulster. After all, I thought, we are not injuring her. We are +but preventing her from injuring another. + +Holmes had sat up upon the couch, and I saw him motion like a man +who is in need of air. A maid rushed across and threw open the +window. At the same instant I saw him raise his hand and at the +signal I tossed my rocket into the room with a cry of "Fire!" The +word was no sooner out of my mouth than the whole crowd of +spectators, well dressed and ill--gentlemen, ostlers, and +servant-maids--joined in a general shriek of "Fire!" Thick clouds +of smoke curled through the room and out at the open window. I +caught a glimpse of rushing figures, and a moment later the voice +of Holmes from within assuring them that it was a false alarm. +Slipping through the shouting crowd I made my way to the corner +of the street, and in ten minutes was rejoiced to find my +friend's arm in mine, and to get away from the scene of uproar. +He walked swiftly and in silence for some few minutes until we +had turned down one of the quiet streets which lead towards the +Edgeware Road. + +"You did it very nicely, Doctor," he remarked. "Nothing could +have been better. It is all right." + +"You have the photograph?" + +"I know where it is." + +"And how did you find out?" + +"She showed me, as I told you she would." + +"I am still in the dark." + +"I do not wish to make a mystery," said he, laughing. "The matter +was perfectly simple. You, of course, saw that everyone in the +street was an accomplice. They were all engaged for the evening." + +"I guessed as much." + +"Then, when the row broke out, I had a little moist red paint in +the palm of my hand. I rushed forward, fell down, clapped my hand +to my face, and became a piteous spectacle. It is an old trick." + +"That also I could fathom." + +"Then they carried me in. She was bound to have me in. What else +could she do? And into her sitting-room, which was the very room +which I suspected. It lay between that and her bedroom, and I was +determined to see which. They laid me on a couch, I motioned for +air, they were compelled to open the window, and you had your +chance." + +"How did that help you?" + +"It was all-important. When a woman thinks that her house is on +fire, her instinct is at once to rush to the thing which she +values most. It is a perfectly overpowering impulse, and I have +more than once taken advantage of it. In the case of the +Darlington substitution scandal it was of use to me, and also in +the Arnsworth Castle business. A married woman grabs at her baby; +an unmarried one reaches for her jewel-box. Now it was clear to +me that our lady of to-day had nothing in the house more precious +to her than what we are in quest of. She would rush to secure it. +The alarm of fire was admirably done. The smoke and shouting were +enough to shake nerves of steel. She responded beautifully. The +photograph is in a recess behind a sliding panel just above the +right bell-pull. She was there in an instant, and I caught a +glimpse of it as she half-drew it out. When I cried out that it +was a false alarm, she replaced it, glanced at the rocket, rushed +from the room, and I have not seen her since. I rose, and, making +my excuses, escaped from the house. I hesitated whether to +attempt to secure the photograph at once; but the coachman had +come in, and as he was watching me narrowly it seemed safer to +wait. A little over-precipitance may ruin all." + +"And now?" I asked. + +"Our quest is practically finished. I shall call with the King +to-morrow, and with you, if you care to come with us. We will be +shown into the sitting-room to wait for the lady, but it is +probable that when she comes she may find neither us nor the +photograph. It might be a satisfaction to his Majesty to regain +it with his own hands." + +"And when will you call?" + +"At eight in the morning. She will not be up, so that we shall +have a clear field. Besides, we must be prompt, for this marriage +may mean a complete change in her life and habits. I must wire to +the King without delay." + +We had reached Baker Street and had stopped at the door. He was +searching his pockets for the key when someone passing said: + +"Good-night, Mister Sherlock Holmes." + +There were several people on the pavement at the time, but the +greeting appeared to come from a slim youth in an ulster who had +hurried by. + +"I've heard that voice before," said Holmes, staring down the +dimly lit street. "Now, I wonder who the deuce that could have +been." + + +III. + +I slept at Baker Street that night, and we were engaged upon our +toast and coffee in the morning when the King of Bohemia rushed +into the room. + +"You have really got it!" he cried, grasping Sherlock Holmes by +either shoulder and looking eagerly into his face. + +"Not yet." + +"But you have hopes?" + +"I have hopes." + +"Then, come. I am all impatience to be gone." + +"We must have a cab." + +"No, my brougham is waiting." + +"Then that will simplify matters." We descended and started off +once more for Briony Lodge. + +"Irene Adler is married," remarked Holmes. + +"Married! When?" + +"Yesterday." + +"But to whom?" + +"To an English lawyer named Norton." + +"But she could not love him." + +"I am in hopes that she does." + +"And why in hopes?" + +"Because it would spare your Majesty all fear of future +annoyance. If the lady loves her husband, she does not love your +Majesty. If she does not love your Majesty, there is no reason +why she should interfere with your Majesty's plan." + +"It is true. And yet--Well! I wish she had been of my own +station! What a queen she would have made!" He relapsed into a +moody silence, which was not broken until we drew up in +Serpentine Avenue. + +The door of Briony Lodge was open, and an elderly woman stood +upon the steps. She watched us with a sardonic eye as we stepped +from the brougham. + +"Mr. Sherlock Holmes, I believe?" said she. + +"I am Mr. Holmes," answered my companion, looking at her with a +questioning and rather startled gaze. + +"Indeed! My mistress told me that you were likely to call. She +left this morning with her husband by the 5:15 train from Charing +Cross for the Continent." + +"What!" Sherlock Holmes staggered back, white with chagrin and +surprise. "Do you mean that she has left England?" + +"Never to return." + +"And the papers?" asked the King hoarsely. "All is lost." + +"We shall see." He pushed past the servant and rushed into the +drawing-room, followed by the King and myself. The furniture was +scattered about in every direction, with dismantled shelves and +open drawers, as if the lady had hurriedly ransacked them before +her flight. Holmes rushed at the bell-pull, tore back a small +sliding shutter, and, plunging in his hand, pulled out a +photograph and a letter. The photograph was of Irene Adler +herself in evening dress, the letter was superscribed to +"Sherlock Holmes, Esq. To be left till called for." My friend +tore it open and we all three read it together. It was dated at +midnight of the preceding night and ran in this way: + +"MY DEAR MR. SHERLOCK HOLMES,--You really did it very well. You +took me in completely. Until after the alarm of fire, I had not a +suspicion. But then, when I found how I had betrayed myself, I +began to think. I had been warned against you months ago. I had +been told that if the King employed an agent it would certainly +be you. And your address had been given me. Yet, with all this, +you made me reveal what you wanted to know. Even after I became +suspicious, I found it hard to think evil of such a dear, kind +old clergyman. But, you know, I have been trained as an actress +myself. Male costume is nothing new to me. I often take advantage +of the freedom which it gives. I sent John, the coachman, to +watch you, ran up stairs, got into my walking-clothes, as I call +them, and came down just as you departed. + +"Well, I followed you to your door, and so made sure that I was +really an object of interest to the celebrated Mr. Sherlock +Holmes. Then I, rather imprudently, wished you good-night, and +started for the Temple to see my husband. + +"We both thought the best resource was flight, when pursued by +so formidable an antagonist; so you will find the nest empty when +you call to-morrow. As to the photograph, your client may rest in +peace. I love and am loved by a better man than he. The King may +do what he will without hindrance from one whom he has cruelly +wronged. I keep it only to safeguard myself, and to preserve a +weapon which will always secure me from any steps which he might +take in the future. I leave a photograph which he might care to +possess; and I remain, dear Mr. Sherlock Holmes, + + "Very truly yours, + "IRENE NORTON, née ADLER." + +"What a woman--oh, what a woman!" cried the King of Bohemia, when +we had all three read this epistle. "Did I not tell you how quick +and resolute she was? Would she not have made an admirable queen? +Is it not a pity that she was not on my level?" + +"From what I have seen of the lady she seems indeed to be on a +very different level to your Majesty," said Holmes coldly. "I am +sorry that I have not been able to bring your Majesty's business +to a more successful conclusion." + +"On the contrary, my dear sir," cried the King; "nothing could be +more successful. I know that her word is inviolate. The +photograph is now as safe as if it were in the fire." + +"I am glad to hear your Majesty say so." + +"I am immensely indebted to you. Pray tell me in what way I can +reward you. This ring--" He slipped an emerald snake ring from +his finger and held it out upon the palm of his hand. + +"Your Majesty has something which I should value even more +highly," said Holmes. + +"You have but to name it." + +"This photograph!" + +The King stared at him in amazement. + +"Irene's photograph!" he cried. "Certainly, if you wish it." + +"I thank your Majesty. Then there is no more to be done in the +matter. I have the honour to wish you a very good-morning." He +bowed, and, turning away without observing the hand which the +King had stretched out to him, he set off in my company for his +chambers. + +And that was how a great scandal threatened to affect the kingdom +of Bohemia, and how the best plans of Mr. Sherlock Holmes were +beaten by a woman's wit. He used to make merry over the +cleverness of women, but I have not heard him do it of late. And +when he speaks of Irene Adler, or when he refers to her +photograph, it is always under the honourable title of the woman. + + + +ADVENTURE II. THE RED-HEADED LEAGUE + +I had called upon my friend, Mr. Sherlock Holmes, one day in the +autumn of last year and found him in deep conversation with a +very stout, florid-faced, elderly gentleman with fiery red hair. +With an apology for my intrusion, I was about to withdraw when +Holmes pulled me abruptly into the room and closed the door +behind me. + +"You could not possibly have come at a better time, my dear +Watson," he said cordially. + +"I was afraid that you were engaged." + +"So I am. Very much so." + +"Then I can wait in the next room." + +"Not at all. This gentleman, Mr. Wilson, has been my partner and +helper in many of my most successful cases, and I have no +doubt that he will be of the utmost use to me in yours also." + +The stout gentleman half rose from his chair and gave a bob of +greeting, with a quick little questioning glance from his small +fat-encircled eyes. + +"Try the settee," said Holmes, relapsing into his armchair and +putting his fingertips together, as was his custom when in +judicial moods. "I know, my dear Watson, that you share my love +of all that is bizarre and outside the conventions and humdrum +routine of everyday life. You have shown your relish for it by +the enthusiasm which has prompted you to chronicle, and, if you +will excuse my saying so, somewhat to embellish so many of my own +little adventures." + +"Your cases have indeed been of the greatest interest to me," I +observed. + +"You will remember that I remarked the other day, just before we +went into the very simple problem presented by Miss Mary +Sutherland, that for strange effects and extraordinary +combinations we must go to life itself, which is always far more +daring than any effort of the imagination." + +"A proposition which I took the liberty of doubting." + +"You did, Doctor, but none the less you must come round to my +view, for otherwise I shall keep on piling fact upon fact on you +until your reason breaks down under them and acknowledges me to +be right. Now, Mr. Jabez Wilson here has been good enough to call +upon me this morning, and to begin a narrative which promises to +be one of the most singular which I have listened to for some +time. You have heard me remark that the strangest and most unique +things are very often connected not with the larger but with the +smaller crimes, and occasionally, indeed, where there is room for +doubt whether any positive crime has been committed. As far as I +have heard it is impossible for me to say whether the present +case is an instance of crime or not, but the course of events is +certainly among the most singular that I have ever listened to. +Perhaps, Mr. Wilson, you would have the great kindness to +recommence your narrative. I ask you not merely because my friend +Dr. Watson has not heard the opening part but also because the +peculiar nature of the story makes me anxious to have every +possible detail from your lips. As a rule, when I have heard some +slight indication of the course of events, I am able to guide +myself by the thousands of other similar cases which occur to my +memory. In the present instance I am forced to admit that the +facts are, to the best of my belief, unique." + +The portly client puffed out his chest with an appearance of some +little pride and pulled a dirty and wrinkled newspaper from the +inside pocket of his greatcoat. As he glanced down the +advertisement column, with his head thrust forward and the paper +flattened out upon his knee, I took a good look at the man and +endeavoured, after the fashion of my companion, to read the +indications which might be presented by his dress or appearance. + +I did not gain very much, however, by my inspection. Our visitor +bore every mark of being an average commonplace British +tradesman, obese, pompous, and slow. He wore rather baggy grey +shepherd's check trousers, a not over-clean black frock-coat, +unbuttoned in the front, and a drab waistcoat with a heavy brassy +Albert chain, and a square pierced bit of metal dangling down as +an ornament. A frayed top-hat and a faded brown overcoat with a +wrinkled velvet collar lay upon a chair beside him. Altogether, +look as I would, there was nothing remarkable about the man save +his blazing red head, and the expression of extreme chagrin and +discontent upon his features. + +Sherlock Holmes' quick eye took in my occupation, and he shook +his head with a smile as he noticed my questioning glances. +"Beyond the obvious facts that he has at some time done manual +labour, that he takes snuff, that he is a Freemason, that he has +been in China, and that he has done a considerable amount of +writing lately, I can deduce nothing else." + +Mr. Jabez Wilson started up in his chair, with his forefinger +upon the paper, but his eyes upon my companion. + +"How, in the name of good-fortune, did you know all that, Mr. +Holmes?" he asked. "How did you know, for example, that I did +manual labour. It's as true as gospel, for I began as a ship's +carpenter." + +"Your hands, my dear sir. Your right hand is quite a size larger +than your left. You have worked with it, and the muscles are more +developed." + +"Well, the snuff, then, and the Freemasonry?" + +"I won't insult your intelligence by telling you how I read that, +especially as, rather against the strict rules of your order, you +use an arc-and-compass breastpin." + +"Ah, of course, I forgot that. But the writing?" + +"What else can be indicated by that right cuff so very shiny for +five inches, and the left one with the smooth patch near the +elbow where you rest it upon the desk?" + +"Well, but China?" + +"The fish that you have tattooed immediately above your right +wrist could only have been done in China. I have made a small +study of tattoo marks and have even contributed to the literature +of the subject. That trick of staining the fishes' scales of a +delicate pink is quite peculiar to China. When, in addition, I +see a Chinese coin hanging from your watch-chain, the matter +becomes even more simple." + +Mr. Jabez Wilson laughed heavily. "Well, I never!" said he. "I +thought at first that you had done something clever, but I see +that there was nothing in it, after all." + +"I begin to think, Watson," said Holmes, "that I make a mistake +in explaining. 'Omne ignotum pro magnifico,' you know, and my +poor little reputation, such as it is, will suffer shipwreck if I +am so candid. Can you not find the advertisement, Mr. Wilson?" + +"Yes, I have got it now," he answered with his thick red finger +planted halfway down the column. "Here it is. This is what began +it all. You just read it for yourself, sir." + +I took the paper from him and read as follows: + +"TO THE RED-HEADED LEAGUE: On account of the bequest of the late +Ezekiah Hopkins, of Lebanon, Pennsylvania, U. S. A., there is now +another vacancy open which entitles a member of the League to a +salary of 4 pounds a week for purely nominal services. All +red-headed men who are sound in body and mind and above the age +of twenty-one years, are eligible. Apply in person on Monday, at +eleven o'clock, to Duncan Ross, at the offices of the League, 7 +Pope's Court, Fleet Street." + +"What on earth does this mean?" I ejaculated after I had twice +read over the extraordinary announcement. + +Holmes chuckled and wriggled in his chair, as was his habit when +in high spirits. "It is a little off the beaten track, isn't it?" +said he. "And now, Mr. Wilson, off you go at scratch and tell us +all about yourself, your household, and the effect which this +advertisement had upon your fortunes. You will first make a note, +Doctor, of the paper and the date." + +"It is The Morning Chronicle of April 27, 1890. Just two months +ago." + +"Very good. Now, Mr. Wilson?" + +"Well, it is just as I have been telling you, Mr. Sherlock +Holmes," said Jabez Wilson, mopping his forehead; "I have a small +pawnbroker's business at Coburg Square, near the City. It's not a +very large affair, and of late years it has not done more than +just give me a living. I used to be able to keep two assistants, +but now I only keep one; and I would have a job to pay him but +that he is willing to come for half wages so as to learn the +business." + +"What is the name of this obliging youth?" asked Sherlock Holmes. + +"His name is Vincent Spaulding, and he's not such a youth, +either. It's hard to say his age. I should not wish a smarter +assistant, Mr. Holmes; and I know very well that he could better +himself and earn twice what I am able to give him. But, after +all, if he is satisfied, why should I put ideas in his head?" + +"Why, indeed? You seem most fortunate in having an employé who +comes under the full market price. It is not a common experience +among employers in this age. I don't know that your assistant is +not as remarkable as your advertisement." + +"Oh, he has his faults, too," said Mr. Wilson. "Never was such a +fellow for photography. Snapping away with a camera when he ought +to be improving his mind, and then diving down into the cellar +like a rabbit into its hole to develop his pictures. That is his +main fault, but on the whole he's a good worker. There's no vice +in him." + +"He is still with you, I presume?" + +"Yes, sir. He and a girl of fourteen, who does a bit of simple +cooking and keeps the place clean--that's all I have in the +house, for I am a widower and never had any family. We live very +quietly, sir, the three of us; and we keep a roof over our heads +and pay our debts, if we do nothing more. + +"The first thing that put us out was that advertisement. +Spaulding, he came down into the office just this day eight +weeks, with this very paper in his hand, and he says: + +"'I wish to the Lord, Mr. Wilson, that I was a red-headed man.' + +"'Why that?' I asks. + +"'Why,' says he, 'here's another vacancy on the League of the +Red-headed Men. It's worth quite a little fortune to any man who +gets it, and I understand that there are more vacancies than +there are men, so that the trustees are at their wits' end what +to do with the money. If my hair would only change colour, here's +a nice little crib all ready for me to step into.' + +"'Why, what is it, then?' I asked. You see, Mr. Holmes, I am a +very stay-at-home man, and as my business came to me instead of +my having to go to it, I was often weeks on end without putting +my foot over the door-mat. In that way I didn't know much of what +was going on outside, and I was always glad of a bit of news. + +"'Have you never heard of the League of the Red-headed Men?' he +asked with his eyes open. + +"'Never.' + +"'Why, I wonder at that, for you are eligible yourself for one +of the vacancies.' + +"'And what are they worth?' I asked. + +"'Oh, merely a couple of hundred a year, but the work is slight, +and it need not interfere very much with one's other +occupations.' + +"Well, you can easily think that that made me prick up my ears, +for the business has not been over-good for some years, and an +extra couple of hundred would have been very handy. + +"'Tell me all about it,' said I. + +"'Well,' said he, showing me the advertisement, 'you can see for +yourself that the League has a vacancy, and there is the address +where you should apply for particulars. As far as I can make out, +the League was founded by an American millionaire, Ezekiah +Hopkins, who was very peculiar in his ways. He was himself +red-headed, and he had a great sympathy for all red-headed men; +so when he died it was found that he had left his enormous +fortune in the hands of trustees, with instructions to apply the +interest to the providing of easy berths to men whose hair is of +that colour. From all I hear it is splendid pay and very little to +do.' + +"'But,' said I, 'there would be millions of red-headed men who +would apply.' + +"'Not so many as you might think,' he answered. 'You see it is +really confined to Londoners, and to grown men. This American had +started from London when he was young, and he wanted to do the +old town a good turn. Then, again, I have heard it is no use your +applying if your hair is light red, or dark red, or anything but +real bright, blazing, fiery red. Now, if you cared to apply, Mr. +Wilson, you would just walk in; but perhaps it would hardly be +worth your while to put yourself out of the way for the sake of a +few hundred pounds.' + +"Now, it is a fact, gentlemen, as you may see for yourselves, +that my hair is of a very full and rich tint, so that it seemed +to me that if there was to be any competition in the matter I +stood as good a chance as any man that I had ever met. Vincent +Spaulding seemed to know so much about it that I thought he might +prove useful, so I just ordered him to put up the shutters for +the day and to come right away with me. He was very willing to +have a holiday, so we shut the business up and started off for +the address that was given us in the advertisement. + +"I never hope to see such a sight as that again, Mr. Holmes. From +north, south, east, and west every man who had a shade of red in +his hair had tramped into the city to answer the advertisement. +Fleet Street was choked with red-headed folk, and Pope's Court +looked like a coster's orange barrow. I should not have thought +there were so many in the whole country as were brought together +by that single advertisement. Every shade of colour they +were--straw, lemon, orange, brick, Irish-setter, liver, clay; +but, as Spaulding said, there were not many who had the real +vivid flame-coloured tint. When I saw how many were waiting, I +would have given it up in despair; but Spaulding would not hear +of it. How he did it I could not imagine, but he pushed and +pulled and butted until he got me through the crowd, and right up +to the steps which led to the office. There was a double stream +upon the stair, some going up in hope, and some coming back +dejected; but we wedged in as well as we could and soon found +ourselves in the office." + +"Your experience has been a most entertaining one," remarked +Holmes as his client paused and refreshed his memory with a huge +pinch of snuff. "Pray continue your very interesting statement." + +"There was nothing in the office but a couple of wooden chairs +and a deal table, behind which sat a small man with a head that +was even redder than mine. He said a few words to each candidate +as he came up, and then he always managed to find some fault in +them which would disqualify them. Getting a vacancy did not seem +to be such a very easy matter, after all. However, when our turn +came the little man was much more favourable to me than to any of +the others, and he closed the door as we entered, so that he +might have a private word with us. + +"'This is Mr. Jabez Wilson,' said my assistant, 'and he is +willing to fill a vacancy in the League.' + +"'And he is admirably suited for it,' the other answered. 'He has +every requirement. I cannot recall when I have seen anything so +fine.' He took a step backward, cocked his head on one side, and +gazed at my hair until I felt quite bashful. Then suddenly he +plunged forward, wrung my hand, and congratulated me warmly on my +success. + +"'It would be injustice to hesitate,' said he. 'You will, +however, I am sure, excuse me for taking an obvious precaution.' +With that he seized my hair in both his hands, and tugged until I +yelled with the pain. 'There is water in your eyes,' said he as +he released me. 'I perceive that all is as it should be. But we +have to be careful, for we have twice been deceived by wigs and +once by paint. I could tell you tales of cobbler's wax which +would disgust you with human nature.' He stepped over to the +window and shouted through it at the top of his voice that the +vacancy was filled. A groan of disappointment came up from below, +and the folk all trooped away in different directions until there +was not a red-head to be seen except my own and that of the +manager. + +"'My name,' said he, 'is Mr. Duncan Ross, and I am myself one of +the pensioners upon the fund left by our noble benefactor. Are +you a married man, Mr. Wilson? Have you a family?' + +"I answered that I had not. + +"His face fell immediately. + +"'Dear me!' he said gravely, 'that is very serious indeed! I am +sorry to hear you say that. The fund was, of course, for the +propagation and spread of the red-heads as well as for their +maintenance. It is exceedingly unfortunate that you should be a +bachelor.' + +"My face lengthened at this, Mr. Holmes, for I thought that I was +not to have the vacancy after all; but after thinking it over for +a few minutes he said that it would be all right. + +"'In the case of another,' said he, 'the objection might be +fatal, but we must stretch a point in favour of a man with such a +head of hair as yours. When shall you be able to enter upon your +new duties?' + +"'Well, it is a little awkward, for I have a business already,' +said I. + +"'Oh, never mind about that, Mr. Wilson!' said Vincent Spaulding. +'I should be able to look after that for you.' + +"'What would be the hours?' I asked. + +"'Ten to two.' + +"Now a pawnbroker's business is mostly done of an evening, Mr. +Holmes, especially Thursday and Friday evening, which is just +before pay-day; so it would suit me very well to earn a little in +the mornings. Besides, I knew that my assistant was a good man, +and that he would see to anything that turned up. + +"'That would suit me very well,' said I. 'And the pay?' + +"'Is 4 pounds a week.' + +"'And the work?' + +"'Is purely nominal.' + +"'What do you call purely nominal?' + +"'Well, you have to be in the office, or at least in the +building, the whole time. If you leave, you forfeit your whole +position forever. The will is very clear upon that point. You +don't comply with the conditions if you budge from the office +during that time.' + +"'It's only four hours a day, and I should not think of leaving,' +said I. + +"'No excuse will avail,' said Mr. Duncan Ross; 'neither sickness +nor business nor anything else. There you must stay, or you lose +your billet.' + +"'And the work?' + +"'Is to copy out the "Encyclopaedia Britannica." There is the first +volume of it in that press. You must find your own ink, pens, and +blotting-paper, but we provide this table and chair. Will you be +ready to-morrow?' + +"'Certainly,' I answered. + +"'Then, good-bye, Mr. Jabez Wilson, and let me congratulate you +once more on the important position which you have been fortunate +enough to gain.' He bowed me out of the room and I went home with +my assistant, hardly knowing what to say or do, I was so pleased +at my own good fortune. + +"Well, I thought over the matter all day, and by evening I was in +low spirits again; for I had quite persuaded myself that the +whole affair must be some great hoax or fraud, though what its +object might be I could not imagine. It seemed altogether past +belief that anyone could make such a will, or that they would pay +such a sum for doing anything so simple as copying out the +'Encyclopaedia Britannica.' Vincent Spaulding did what he could to +cheer me up, but by bedtime I had reasoned myself out of the +whole thing. However, in the morning I determined to have a look +at it anyhow, so I bought a penny bottle of ink, and with a +quill-pen, and seven sheets of foolscap paper, I started off for +Pope's Court. + +"Well, to my surprise and delight, everything was as right as +possible. The table was set out ready for me, and Mr. Duncan Ross +was there to see that I got fairly to work. He started me off +upon the letter A, and then he left me; but he would drop in from +time to time to see that all was right with me. At two o'clock he +bade me good-day, complimented me upon the amount that I had +written, and locked the door of the office after me. + +"This went on day after day, Mr. Holmes, and on Saturday the +manager came in and planked down four golden sovereigns for my +week's work. It was the same next week, and the same the week +after. Every morning I was there at ten, and every afternoon I +left at two. By degrees Mr. Duncan Ross took to coming in only +once of a morning, and then, after a time, he did not come in at +all. Still, of course, I never dared to leave the room for an +instant, for I was not sure when he might come, and the billet +was such a good one, and suited me so well, that I would not risk +the loss of it. + +"Eight weeks passed away like this, and I had written about +Abbots and Archery and Armour and Architecture and Attica, and +hoped with diligence that I might get on to the B's before very +long. It cost me something in foolscap, and I had pretty nearly +filled a shelf with my writings. And then suddenly the whole +business came to an end." + +"To an end?" + +"Yes, sir. And no later than this morning. I went to my work as +usual at ten o'clock, but the door was shut and locked, with a +little square of cardboard hammered on to the middle of the +panel with a tack. Here it is, and you can read for yourself." + +He held up a piece of white cardboard about the size of a sheet +of note-paper. It read in this fashion: + + THE RED-HEADED LEAGUE + + IS + + DISSOLVED. + + October 9, 1890. + +Sherlock Holmes and I surveyed this curt announcement and the +rueful face behind it, until the comical side of the affair so +completely overtopped every other consideration that we both +burst out into a roar of laughter. + +"I cannot see that there is anything very funny," cried our +client, flushing up to the roots of his flaming head. "If you can +do nothing better than laugh at me, I can go elsewhere." + +"No, no," cried Holmes, shoving him back into the chair from +which he had half risen. "I really wouldn't miss your case for +the world. It is most refreshingly unusual. But there is, if you +will excuse my saying so, something just a little funny about it. +Pray what steps did you take when you found the card upon the +door?" + +"I was staggered, sir. I did not know what to do. Then I called +at the offices round, but none of them seemed to know anything +about it. Finally, I went to the landlord, who is an accountant +living on the ground-floor, and I asked him if he could tell me +what had become of the Red-headed League. He said that he had +never heard of any such body. Then I asked him who Mr. Duncan +Ross was. He answered that the name was new to him. + +"'Well,' said I, 'the gentleman at No. 4.' + +"'What, the red-headed man?' + +"'Yes.' + +"'Oh,' said he, 'his name was William Morris. He was a solicitor +and was using my room as a temporary convenience until his new +premises were ready. He moved out yesterday.' + +"'Where could I find him?' + +"'Oh, at his new offices. He did tell me the address. Yes, 17 +King Edward Street, near St. Paul's.' + +"I started off, Mr. Holmes, but when I got to that address it was +a manufactory of artificial knee-caps, and no one in it had ever +heard of either Mr. William Morris or Mr. Duncan Ross." + +"And what did you do then?" asked Holmes. + +"I went home to Saxe-Coburg Square, and I took the advice of my +assistant. But he could not help me in any way. He could only say +that if I waited I should hear by post. But that was not quite +good enough, Mr. Holmes. I did not wish to lose such a place +without a struggle, so, as I had heard that you were good enough +to give advice to poor folk who were in need of it, I came right +away to you." + +"And you did very wisely," said Holmes. "Your case is an +exceedingly remarkable one, and I shall be happy to look into it. +From what you have told me I think that it is possible that +graver issues hang from it than might at first sight appear." + +"Grave enough!" said Mr. Jabez Wilson. "Why, I have lost four +pound a week." + +"As far as you are personally concerned," remarked Holmes, "I do +not see that you have any grievance against this extraordinary +league. On the contrary, you are, as I understand, richer by some +30 pounds, to say nothing of the minute knowledge which you have +gained on every subject which comes under the letter A. You have +lost nothing by them." + +"No, sir. But I want to find out about them, and who they are, +and what their object was in playing this prank--if it was a +prank--upon me. It was a pretty expensive joke for them, for it +cost them two and thirty pounds." + +"We shall endeavour to clear up these points for you. And, first, +one or two questions, Mr. Wilson. This assistant of yours who +first called your attention to the advertisement--how long had he +been with you?" + +"About a month then." + +"How did he come?" + +"In answer to an advertisement." + +"Was he the only applicant?" + +"No, I had a dozen." + +"Why did you pick him?" + +"Because he was handy and would come cheap." + +"At half-wages, in fact." + +"Yes." + +"What is he like, this Vincent Spaulding?" + +"Small, stout-built, very quick in his ways, no hair on his face, +though he's not short of thirty. Has a white splash of acid upon +his forehead." + +Holmes sat up in his chair in considerable excitement. "I thought +as much," said he. "Have you ever observed that his ears are +pierced for earrings?" + +"Yes, sir. He told me that a gipsy had done it for him when he +was a lad." + +"Hum!" said Holmes, sinking back in deep thought. "He is still +with you?" + +"Oh, yes, sir; I have only just left him." + +"And has your business been attended to in your absence?" + +"Nothing to complain of, sir. There's never very much to do of a +morning." + +"That will do, Mr. Wilson. I shall be happy to give you an +opinion upon the subject in the course of a day or two. To-day is +Saturday, and I hope that by Monday we may come to a conclusion." + +"Well, Watson," said Holmes when our visitor had left us, "what +do you make of it all?" + +"I make nothing of it," I answered frankly. "It is a most +mysterious business." + +"As a rule," said Holmes, "the more bizarre a thing is the less +mysterious it proves to be. It is your commonplace, featureless +crimes which are really puzzling, just as a commonplace face is +the most difficult to identify. But I must be prompt over this +matter." + +"What are you going to do, then?" I asked. + +"To smoke," he answered. "It is quite a three pipe problem, and I +beg that you won't speak to me for fifty minutes." He curled +himself up in his chair, with his thin knees drawn up to his +hawk-like nose, and there he sat with his eyes closed and his +black clay pipe thrusting out like the bill of some strange bird. +I had come to the conclusion that he had dropped asleep, and +indeed was nodding myself, when he suddenly sprang out of his +chair with the gesture of a man who has made up his mind and put +his pipe down upon the mantelpiece. + +"Sarasate plays at the St. James's Hall this afternoon," he +remarked. "What do you think, Watson? Could your patients spare +you for a few hours?" + +"I have nothing to do to-day. My practice is never very +absorbing." + +"Then put on your hat and come. I am going through the City +first, and we can have some lunch on the way. I observe that +there is a good deal of German music on the programme, which is +rather more to my taste than Italian or French. It is +introspective, and I want to introspect. Come along!" + +We travelled by the Underground as far as Aldersgate; and a short +walk took us to Saxe-Coburg Square, the scene of the singular +story which we had listened to in the morning. It was a poky, +little, shabby-genteel place, where four lines of dingy +two-storied brick houses looked out into a small railed-in +enclosure, where a lawn of weedy grass and a few clumps of faded +laurel-bushes made a hard fight against a smoke-laden and +uncongenial atmosphere. Three gilt balls and a brown board with +"JABEZ WILSON" in white letters, upon a corner house, announced +the place where our red-headed client carried on his business. +Sherlock Holmes stopped in front of it with his head on one side +and looked it all over, with his eyes shining brightly between +puckered lids. Then he walked slowly up the street, and then down +again to the corner, still looking keenly at the houses. Finally +he returned to the pawnbroker's, and, having thumped vigorously +upon the pavement with his stick two or three times, he went up +to the door and knocked. It was instantly opened by a +bright-looking, clean-shaven young fellow, who asked him to step +in. + +"Thank you," said Holmes, "I only wished to ask you how you would +go from here to the Strand." + +"Third right, fourth left," answered the assistant promptly, +closing the door. + +"Smart fellow, that," observed Holmes as we walked away. "He is, +in my judgment, the fourth smartest man in London, and for daring +I am not sure that he has not a claim to be third. I have known +something of him before." + +"Evidently," said I, "Mr. Wilson's assistant counts for a good +deal in this mystery of the Red-headed League. I am sure that you +inquired your way merely in order that you might see him." + +"Not him." + +"What then?" + +"The knees of his trousers." + +"And what did you see?" + +"What I expected to see." + +"Why did you beat the pavement?" + +"My dear doctor, this is a time for observation, not for talk. We +are spies in an enemy's country. We know something of Saxe-Coburg +Square. Let us now explore the parts which lie behind it." + +The road in which we found ourselves as we turned round the +corner from the retired Saxe-Coburg Square presented as great a +contrast to it as the front of a picture does to the back. It was +one of the main arteries which conveyed the traffic of the City +to the north and west. The roadway was blocked with the immense +stream of commerce flowing in a double tide inward and outward, +while the footpaths were black with the hurrying swarm of +pedestrians. It was difficult to realise as we looked at the line +of fine shops and stately business premises that they really +abutted on the other side upon the faded and stagnant square +which we had just quitted. + +"Let me see," said Holmes, standing at the corner and glancing +along the line, "I should like just to remember the order of the +houses here. It is a hobby of mine to have an exact knowledge of +London. There is Mortimer's, the tobacconist, the little +newspaper shop, the Coburg branch of the City and Suburban Bank, +the Vegetarian Restaurant, and McFarlane's carriage-building +depot. That carries us right on to the other block. And now, +Doctor, we've done our work, so it's time we had some play. A +sandwich and a cup of coffee, and then off to violin-land, where +all is sweetness and delicacy and harmony, and there are no +red-headed clients to vex us with their conundrums." + +My friend was an enthusiastic musician, being himself not only a +very capable performer but a composer of no ordinary merit. All +the afternoon he sat in the stalls wrapped in the most perfect +happiness, gently waving his long, thin fingers in time to the +music, while his gently smiling face and his languid, dreamy eyes +were as unlike those of Holmes the sleuth-hound, Holmes the +relentless, keen-witted, ready-handed criminal agent, as it was +possible to conceive. In his singular character the dual nature +alternately asserted itself, and his extreme exactness and +astuteness represented, as I have often thought, the reaction +against the poetic and contemplative mood which occasionally +predominated in him. The swing of his nature took him from +extreme languor to devouring energy; and, as I knew well, he was +never so truly formidable as when, for days on end, he had been +lounging in his armchair amid his improvisations and his +black-letter editions. Then it was that the lust of the chase +would suddenly come upon him, and that his brilliant reasoning +power would rise to the level of intuition, until those who were +unacquainted with his methods would look askance at him as on a +man whose knowledge was not that of other mortals. When I saw him +that afternoon so enwrapped in the music at St. James's Hall I +felt that an evil time might be coming upon those whom he had set +himself to hunt down. + +"You want to go home, no doubt, Doctor," he remarked as we +emerged. + +"Yes, it would be as well." + +"And I have some business to do which will take some hours. This +business at Coburg Square is serious." + +"Why serious?" + +"A considerable crime is in contemplation. I have every reason to +believe that we shall be in time to stop it. But to-day being +Saturday rather complicates matters. I shall want your help +to-night." + +"At what time?" + +"Ten will be early enough." + +"I shall be at Baker Street at ten." + +"Very well. And, I say, Doctor, there may be some little danger, +so kindly put your army revolver in your pocket." He waved his +hand, turned on his heel, and disappeared in an instant among the +crowd. + +I trust that I am not more dense than my neighbours, but I was +always oppressed with a sense of my own stupidity in my dealings +with Sherlock Holmes. Here I had heard what he had heard, I had +seen what he had seen, and yet from his words it was evident that +he saw clearly not only what had happened but what was about to +happen, while to me the whole business was still confused and +grotesque. As I drove home to my house in Kensington I thought +over it all, from the extraordinary story of the red-headed +copier of the "Encyclopaedia" down to the visit to Saxe-Coburg +Square, and the ominous words with which he had parted from me. +What was this nocturnal expedition, and why should I go armed? +Where were we going, and what were we to do? I had the hint from +Holmes that this smooth-faced pawnbroker's assistant was a +formidable man--a man who might play a deep game. I tried to +puzzle it out, but gave it up in despair and set the matter aside +until night should bring an explanation. + +It was a quarter-past nine when I started from home and made my +way across the Park, and so through Oxford Street to Baker +Street. Two hansoms were standing at the door, and as I entered +the passage I heard the sound of voices from above. On entering +his room I found Holmes in animated conversation with two men, +one of whom I recognised as Peter Jones, the official police +agent, while the other was a long, thin, sad-faced man, with a +very shiny hat and oppressively respectable frock-coat. + +"Ha! Our party is complete," said Holmes, buttoning up his +pea-jacket and taking his heavy hunting crop from the rack. +"Watson, I think you know Mr. Jones, of Scotland Yard? Let me +introduce you to Mr. Merryweather, who is to be our companion in +to-night's adventure." + +"We're hunting in couples again, Doctor, you see," said Jones in +his consequential way. "Our friend here is a wonderful man for +starting a chase. All he wants is an old dog to help him to do +the running down." + +"I hope a wild goose may not prove to be the end of our chase," +observed Mr. Merryweather gloomily. + +"You may place considerable confidence in Mr. Holmes, sir," said +the police agent loftily. "He has his own little methods, which +are, if he won't mind my saying so, just a little too theoretical +and fantastic, but he has the makings of a detective in him. It +is not too much to say that once or twice, as in that business of +the Sholto murder and the Agra treasure, he has been more nearly +correct than the official force." + +"Oh, if you say so, Mr. Jones, it is all right," said the +stranger with deference. "Still, I confess that I miss my rubber. +It is the first Saturday night for seven-and-twenty years that I +have not had my rubber." + +"I think you will find," said Sherlock Holmes, "that you will +play for a higher stake to-night than you have ever done yet, and +that the play will be more exciting. For you, Mr. Merryweather, +the stake will be some 30,000 pounds; and for you, Jones, it will +be the man upon whom you wish to lay your hands." + +"John Clay, the murderer, thief, smasher, and forger. He's a +young man, Mr. Merryweather, but he is at the head of his +profession, and I would rather have my bracelets on him than on +any criminal in London. He's a remarkable man, is young John +Clay. His grandfather was a royal duke, and he himself has been +to Eton and Oxford. His brain is as cunning as his fingers, and +though we meet signs of him at every turn, we never know where to +find the man himself. He'll crack a crib in Scotland one week, +and be raising money to build an orphanage in Cornwall the next. +I've been on his track for years and have never set eyes on him +yet." + +"I hope that I may have the pleasure of introducing you to-night. +I've had one or two little turns also with Mr. John Clay, and I +agree with you that he is at the head of his profession. It is +past ten, however, and quite time that we started. If you two +will take the first hansom, Watson and I will follow in the +second." + +Sherlock Holmes was not very communicative during the long drive +and lay back in the cab humming the tunes which he had heard in +the afternoon. We rattled through an endless labyrinth of gas-lit +streets until we emerged into Farrington Street. + +"We are close there now," my friend remarked. "This fellow +Merryweather is a bank director, and personally interested in the +matter. I thought it as well to have Jones with us also. He is +not a bad fellow, though an absolute imbecile in his profession. +He has one positive virtue. He is as brave as a bulldog and as +tenacious as a lobster if he gets his claws upon anyone. Here we +are, and they are waiting for us." + +We had reached the same crowded thoroughfare in which we had +found ourselves in the morning. Our cabs were dismissed, and, +following the guidance of Mr. Merryweather, we passed down a +narrow passage and through a side door, which he opened for us. +Within there was a small corridor, which ended in a very massive +iron gate. This also was opened, and led down a flight of winding +stone steps, which terminated at another formidable gate. Mr. +Merryweather stopped to light a lantern, and then conducted us +down a dark, earth-smelling passage, and so, after opening a +third door, into a huge vault or cellar, which was piled all +round with crates and massive boxes. + +"You are not very vulnerable from above," Holmes remarked as he +held up the lantern and gazed about him. + +"Nor from below," said Mr. Merryweather, striking his stick upon +the flags which lined the floor. "Why, dear me, it sounds quite +hollow!" he remarked, looking up in surprise. + +"I must really ask you to be a little more quiet!" said Holmes +severely. "You have already imperilled the whole success of our +expedition. Might I beg that you would have the goodness to sit +down upon one of those boxes, and not to interfere?" + +The solemn Mr. Merryweather perched himself upon a crate, with a +very injured expression upon his face, while Holmes fell upon his +knees upon the floor and, with the lantern and a magnifying lens, +began to examine minutely the cracks between the stones. A few +seconds sufficed to satisfy him, for he sprang to his feet again +and put his glass in his pocket. + +"We have at least an hour before us," he remarked, "for they can +hardly take any steps until the good pawnbroker is safely in bed. +Then they will not lose a minute, for the sooner they do their +work the longer time they will have for their escape. We are at +present, Doctor--as no doubt you have divined--in the cellar of +the City branch of one of the principal London banks. Mr. +Merryweather is the chairman of directors, and he will explain to +you that there are reasons why the more daring criminals of +London should take a considerable interest in this cellar at +present." + +"It is our French gold," whispered the director. "We have had +several warnings that an attempt might be made upon it." + +"Your French gold?" + +"Yes. We had occasion some months ago to strengthen our resources +and borrowed for that purpose 30,000 napoleons from the Bank of +France. It has become known that we have never had occasion to +unpack the money, and that it is still lying in our cellar. The +crate upon which I sit contains 2,000 napoleons packed between +layers of lead foil. Our reserve of bullion is much larger at +present than is usually kept in a single branch office, and the +directors have had misgivings upon the subject." + +"Which were very well justified," observed Holmes. "And now it is +time that we arranged our little plans. I expect that within an +hour matters will come to a head. In the meantime Mr. +Merryweather, we must put the screen over that dark lantern." + +"And sit in the dark?" + +"I am afraid so. I had brought a pack of cards in my pocket, and +I thought that, as we were a partie carrée, you might have your +rubber after all. But I see that the enemy's preparations have +gone so far that we cannot risk the presence of a light. And, +first of all, we must choose our positions. These are daring men, +and though we shall take them at a disadvantage, they may do us +some harm unless we are careful. I shall stand behind this crate, +and do you conceal yourselves behind those. Then, when I flash a +light upon them, close in swiftly. If they fire, Watson, have no +compunction about shooting them down." + +I placed my revolver, cocked, upon the top of the wooden case +behind which I crouched. Holmes shot the slide across the front +of his lantern and left us in pitch darkness--such an absolute +darkness as I have never before experienced. The smell of hot +metal remained to assure us that the light was still there, ready +to flash out at a moment's notice. To me, with my nerves worked +up to a pitch of expectancy, there was something depressing and +subduing in the sudden gloom, and in the cold dank air of the +vault. + +"They have but one retreat," whispered Holmes. "That is back +through the house into Saxe-Coburg Square. I hope that you have +done what I asked you, Jones?" + +"I have an inspector and two officers waiting at the front door." + +"Then we have stopped all the holes. And now we must be silent +and wait." + +What a time it seemed! From comparing notes afterwards it was but +an hour and a quarter, yet it appeared to me that the night must +have almost gone and the dawn be breaking above us. My limbs +were weary and stiff, for I feared to change my position; yet my +nerves were worked up to the highest pitch of tension, and my +hearing was so acute that I could not only hear the gentle +breathing of my companions, but I could distinguish the deeper, +heavier in-breath of the bulky Jones from the thin, sighing note +of the bank director. From my position I could look over the case +in the direction of the floor. Suddenly my eyes caught the glint +of a light. + +At first it was but a lurid spark upon the stone pavement. Then +it lengthened out until it became a yellow line, and then, +without any warning or sound, a gash seemed to open and a hand +appeared, a white, almost womanly hand, which felt about in the +centre of the little area of light. For a minute or more the +hand, with its writhing fingers, protruded out of the floor. Then +it was withdrawn as suddenly as it appeared, and all was dark +again save the single lurid spark which marked a chink between +the stones. + +Its disappearance, however, was but momentary. With a rending, +tearing sound, one of the broad, white stones turned over upon +its side and left a square, gaping hole, through which streamed +the light of a lantern. Over the edge there peeped a clean-cut, +boyish face, which looked keenly about it, and then, with a hand +on either side of the aperture, drew itself shoulder-high and +waist-high, until one knee rested upon the edge. In another +instant he stood at the side of the hole and was hauling after +him a companion, lithe and small like himself, with a pale face +and a shock of very red hair. + +"It's all clear," he whispered. "Have you the chisel and the +bags? Great Scott! Jump, Archie, jump, and I'll swing for it!" + +Sherlock Holmes had sprung out and seized the intruder by the +collar. The other dived down the hole, and I heard the sound of +rending cloth as Jones clutched at his skirts. The light flashed +upon the barrel of a revolver, but Holmes' hunting crop came +down on the man's wrist, and the pistol clinked upon the stone +floor. + +"It's no use, John Clay," said Holmes blandly. "You have no +chance at all." + +"So I see," the other answered with the utmost coolness. "I fancy +that my pal is all right, though I see you have got his +coat-tails." + +"There are three men waiting for him at the door," said Holmes. + +"Oh, indeed! You seem to have done the thing very completely. I +must compliment you." + +"And I you," Holmes answered. "Your red-headed idea was very new +and effective." + +"You'll see your pal again presently," said Jones. "He's quicker +at climbing down holes than I am. Just hold out while I fix the +derbies." + +"I beg that you will not touch me with your filthy hands," +remarked our prisoner as the handcuffs clattered upon his wrists. +"You may not be aware that I have royal blood in my veins. Have +the goodness, also, when you address me always to say 'sir' and +'please.'" + +"All right," said Jones with a stare and a snigger. "Well, would +you please, sir, march upstairs, where we can get a cab to carry +your Highness to the police-station?" + +"That is better," said John Clay serenely. He made a sweeping bow +to the three of us and walked quietly off in the custody of the +detective. + +"Really, Mr. Holmes," said Mr. Merryweather as we followed them +from the cellar, "I do not know how the bank can thank you or +repay you. There is no doubt that you have detected and defeated +in the most complete manner one of the most determined attempts +at bank robbery that have ever come within my experience." + +"I have had one or two little scores of my own to settle with Mr. +John Clay," said Holmes. "I have been at some small expense over +this matter, which I shall expect the bank to refund, but beyond +that I am amply repaid by having had an experience which is in +many ways unique, and by hearing the very remarkable narrative of +the Red-headed League." + + +"You see, Watson," he explained in the early hours of the morning +as we sat over a glass of whisky and soda in Baker Street, "it +was perfectly obvious from the first that the only possible +object of this rather fantastic business of the advertisement of +the League, and the copying of the 'Encyclopaedia,' must be to get +this not over-bright pawnbroker out of the way for a number of +hours every day. It was a curious way of managing it, but, +really, it would be difficult to suggest a better. The method was +no doubt suggested to Clay's ingenious mind by the colour of his +accomplice's hair. The 4 pounds a week was a lure which must draw +him, and what was it to them, who were playing for thousands? +They put in the advertisement, one rogue has the temporary +office, the other rogue incites the man to apply for it, and +together they manage to secure his absence every morning in the +week. From the time that I heard of the assistant having come for +half wages, it was obvious to me that he had some strong motive +for securing the situation." + +"But how could you guess what the motive was?" + +"Had there been women in the house, I should have suspected a +mere vulgar intrigue. That, however, was out of the question. The +man's business was a small one, and there was nothing in his +house which could account for such elaborate preparations, and +such an expenditure as they were at. It must, then, be something +out of the house. What could it be? I thought of the assistant's +fondness for photography, and his trick of vanishing into the +cellar. The cellar! There was the end of this tangled clue. Then +I made inquiries as to this mysterious assistant and found that I +had to deal with one of the coolest and most daring criminals in +London. He was doing something in the cellar--something which +took many hours a day for months on end. What could it be, once +more? I could think of nothing save that he was running a tunnel +to some other building. + +"So far I had got when we went to visit the scene of action. I +surprised you by beating upon the pavement with my stick. I was +ascertaining whether the cellar stretched out in front or behind. +It was not in front. Then I rang the bell, and, as I hoped, the +assistant answered it. We have had some skirmishes, but we had +never set eyes upon each other before. I hardly looked at his +face. His knees were what I wished to see. You must yourself have +remarked how worn, wrinkled, and stained they were. They spoke of +those hours of burrowing. The only remaining point was what they +were burrowing for. I walked round the corner, saw the City and +Suburban Bank abutted on our friend's premises, and felt that I +had solved my problem. When you drove home after the concert I +called upon Scotland Yard and upon the chairman of the bank +directors, with the result that you have seen." + +"And how could you tell that they would make their attempt +to-night?" I asked. + +"Well, when they closed their League offices that was a sign that +they cared no longer about Mr. Jabez Wilson's presence--in other +words, that they had completed their tunnel. But it was essential +that they should use it soon, as it might be discovered, or the +bullion might be removed. Saturday would suit them better than +any other day, as it would give them two days for their escape. +For all these reasons I expected them to come to-night." + +"You reasoned it out beautifully," I exclaimed in unfeigned +admiration. "It is so long a chain, and yet every link rings +true." + +"It saved me from ennui," he answered, yawning. "Alas! I already +feel it closing in upon me. My life is spent in one long effort +to escape from the commonplaces of existence. These little +problems help me to do so." + +"And you are a benefactor of the race," said I. + +He shrugged his shoulders. "Well, perhaps, after all, it is of +some little use," he remarked. "'L'homme c'est rien--l'oeuvre +c'est tout,' as Gustave Flaubert wrote to George Sand." + + + +ADVENTURE III. A CASE OF IDENTITY + +"My dear fellow," said Sherlock Holmes as we sat on either side +of the fire in his lodgings at Baker Street, "life is infinitely +stranger than anything which the mind of man could invent. We +would not dare to conceive the things which are really mere +commonplaces of existence. If we could fly out of that window +hand in hand, hover over this great city, gently remove the +roofs, and peep in at the queer things which are going on, the +strange coincidences, the plannings, the cross-purposes, the +wonderful chains of events, working through generations, and +leading to the most outré results, it would make all fiction with +its conventionalities and foreseen conclusions most stale and +unprofitable." + +"And yet I am not convinced of it," I answered. "The cases which +come to light in the papers are, as a rule, bald enough, and +vulgar enough. We have in our police reports realism pushed to +its extreme limits, and yet the result is, it must be confessed, +neither fascinating nor artistic." + +"A certain selection and discretion must be used in producing a +realistic effect," remarked Holmes. "This is wanting in the +police report, where more stress is laid, perhaps, upon the +platitudes of the magistrate than upon the details, which to an +observer contain the vital essence of the whole matter. Depend +upon it, there is nothing so unnatural as the commonplace." + +I smiled and shook my head. "I can quite understand your thinking +so," I said. "Of course, in your position of unofficial adviser +and helper to everybody who is absolutely puzzled, throughout +three continents, you are brought in contact with all that is +strange and bizarre. But here"--I picked up the morning paper +from the ground--"let us put it to a practical test. Here is the +first heading upon which I come. 'A husband's cruelty to his +wife.' There is half a column of print, but I know without +reading it that it is all perfectly familiar to me. There is, of +course, the other woman, the drink, the push, the blow, the +bruise, the sympathetic sister or landlady. The crudest of +writers could invent nothing more crude." + +"Indeed, your example is an unfortunate one for your argument," +said Holmes, taking the paper and glancing his eye down it. "This +is the Dundas separation case, and, as it happens, I was engaged +in clearing up some small points in connection with it. The +husband was a teetotaler, there was no other woman, and the +conduct complained of was that he had drifted into the habit of +winding up every meal by taking out his false teeth and hurling +them at his wife, which, you will allow, is not an action likely +to occur to the imagination of the average story-teller. Take a +pinch of snuff, Doctor, and acknowledge that I have scored over +you in your example." + +He held out his snuffbox of old gold, with a great amethyst in +the centre of the lid. Its splendour was in such contrast to his +homely ways and simple life that I could not help commenting upon +it. + +"Ah," said he, "I forgot that I had not seen you for some weeks. +It is a little souvenir from the King of Bohemia in return for my +assistance in the case of the Irene Adler papers." + +"And the ring?" I asked, glancing at a remarkable brilliant which +sparkled upon his finger. + +"It was from the reigning family of Holland, though the matter in +which I served them was of such delicacy that I cannot confide it +even to you, who have been good enough to chronicle one or two of +my little problems." + +"And have you any on hand just now?" I asked with interest. + +"Some ten or twelve, but none which present any feature of +interest. They are important, you understand, without being +interesting. Indeed, I have found that it is usually in +unimportant matters that there is a field for the observation, +and for the quick analysis of cause and effect which gives the +charm to an investigation. The larger crimes are apt to be the +simpler, for the bigger the crime the more obvious, as a rule, is +the motive. In these cases, save for one rather intricate matter +which has been referred to me from Marseilles, there is nothing +which presents any features of interest. It is possible, however, +that I may have something better before very many minutes are +over, for this is one of my clients, or I am much mistaken." + +He had risen from his chair and was standing between the parted +blinds gazing down into the dull neutral-tinted London street. +Looking over his shoulder, I saw that on the pavement opposite +there stood a large woman with a heavy fur boa round her neck, +and a large curling red feather in a broad-brimmed hat which was +tilted in a coquettish Duchess of Devonshire fashion over her +ear. From under this great panoply she peeped up in a nervous, +hesitating fashion at our windows, while her body oscillated +backward and forward, and her fingers fidgeted with her glove +buttons. Suddenly, with a plunge, as of the swimmer who leaves +the bank, she hurried across the road, and we heard the sharp +clang of the bell. + +"I have seen those symptoms before," said Holmes, throwing his +cigarette into the fire. "Oscillation upon the pavement always +means an affaire de coeur. She would like advice, but is not sure +that the matter is not too delicate for communication. And yet +even here we may discriminate. When a woman has been seriously +wronged by a man she no longer oscillates, and the usual symptom +is a broken bell wire. Here we may take it that there is a love +matter, but that the maiden is not so much angry as perplexed, or +grieved. But here she comes in person to resolve our doubts." + +As he spoke there was a tap at the door, and the boy in buttons +entered to announce Miss Mary Sutherland, while the lady herself +loomed behind his small black figure like a full-sailed +merchant-man behind a tiny pilot boat. Sherlock Holmes welcomed +her with the easy courtesy for which he was remarkable, and, +having closed the door and bowed her into an armchair, he looked +her over in the minute and yet abstracted fashion which was +peculiar to him. + +"Do you not find," he said, "that with your short sight it is a +little trying to do so much typewriting?" + +"I did at first," she answered, "but now I know where the letters +are without looking." Then, suddenly realising the full purport +of his words, she gave a violent start and looked up, with fear +and astonishment upon her broad, good-humoured face. "You've +heard about me, Mr. Holmes," she cried, "else how could you know +all that?" + +"Never mind," said Holmes, laughing; "it is my business to know +things. Perhaps I have trained myself to see what others +overlook. If not, why should you come to consult me?" + +"I came to you, sir, because I heard of you from Mrs. Etherege, +whose husband you found so easy when the police and everyone had +given him up for dead. Oh, Mr. Holmes, I wish you would do as +much for me. I'm not rich, but still I have a hundred a year in +my own right, besides the little that I make by the machine, and +I would give it all to know what has become of Mr. Hosmer Angel." + +"Why did you come away to consult me in such a hurry?" asked +Sherlock Holmes, with his finger-tips together and his eyes to +the ceiling. + +Again a startled look came over the somewhat vacuous face of Miss +Mary Sutherland. "Yes, I did bang out of the house," she said, +"for it made me angry to see the easy way in which Mr. +Windibank--that is, my father--took it all. He would not go to +the police, and he would not go to you, and so at last, as he +would do nothing and kept on saying that there was no harm done, +it made me mad, and I just on with my things and came right away +to you." + +"Your father," said Holmes, "your stepfather, surely, since the +name is different." + +"Yes, my stepfather. I call him father, though it sounds funny, +too, for he is only five years and two months older than myself." + +"And your mother is alive?" + +"Oh, yes, mother is alive and well. I wasn't best pleased, Mr. +Holmes, when she married again so soon after father's death, and +a man who was nearly fifteen years younger than herself. Father +was a plumber in the Tottenham Court Road, and he left a tidy +business behind him, which mother carried on with Mr. Hardy, the +foreman; but when Mr. Windibank came he made her sell the +business, for he was very superior, being a traveller in wines. +They got 4700 pounds for the goodwill and interest, which wasn't +near as much as father could have got if he had been alive." + +I had expected to see Sherlock Holmes impatient under this +rambling and inconsequential narrative, but, on the contrary, he +had listened with the greatest concentration of attention. + +"Your own little income," he asked, "does it come out of the +business?" + +"Oh, no, sir. It is quite separate and was left me by my uncle +Ned in Auckland. It is in New Zealand stock, paying 4 1/2 per +cent. Two thousand five hundred pounds was the amount, but I can +only touch the interest." + +"You interest me extremely," said Holmes. "And since you draw so +large a sum as a hundred a year, with what you earn into the +bargain, you no doubt travel a little and indulge yourself in +every way. I believe that a single lady can get on very nicely +upon an income of about 60 pounds." + +"I could do with much less than that, Mr. Holmes, but you +understand that as long as I live at home I don't wish to be a +burden to them, and so they have the use of the money just while +I am staying with them. Of course, that is only just for the +time. Mr. Windibank draws my interest every quarter and pays it +over to mother, and I find that I can do pretty well with what I +earn at typewriting. It brings me twopence a sheet, and I can +often do from fifteen to twenty sheets in a day." + +"You have made your position very clear to me," said Holmes. +"This is my friend, Dr. Watson, before whom you can speak as +freely as before myself. Kindly tell us now all about your +connection with Mr. Hosmer Angel." + +A flush stole over Miss Sutherland's face, and she picked +nervously at the fringe of her jacket. "I met him first at the +gasfitters' ball," she said. "They used to send father tickets +when he was alive, and then afterwards they remembered us, and +sent them to mother. Mr. Windibank did not wish us to go. He +never did wish us to go anywhere. He would get quite mad if I +wanted so much as to join a Sunday-school treat. But this time I +was set on going, and I would go; for what right had he to +prevent? He said the folk were not fit for us to know, when all +father's friends were to be there. And he said that I had nothing +fit to wear, when I had my purple plush that I had never so much +as taken out of the drawer. At last, when nothing else would do, +he went off to France upon the business of the firm, but we went, +mother and I, with Mr. Hardy, who used to be our foreman, and it +was there I met Mr. Hosmer Angel." + +"I suppose," said Holmes, "that when Mr. Windibank came back from +France he was very annoyed at your having gone to the ball." + +"Oh, well, he was very good about it. He laughed, I remember, and +shrugged his shoulders, and said there was no use denying +anything to a woman, for she would have her way." + +"I see. Then at the gasfitters' ball you met, as I understand, a +gentleman called Mr. Hosmer Angel." + +"Yes, sir. I met him that night, and he called next day to ask if +we had got home all safe, and after that we met him--that is to +say, Mr. Holmes, I met him twice for walks, but after that father +came back again, and Mr. Hosmer Angel could not come to the house +any more." + +"No?" + +"Well, you know father didn't like anything of the sort. He +wouldn't have any visitors if he could help it, and he used to +say that a woman should be happy in her own family circle. But +then, as I used to say to mother, a woman wants her own circle to +begin with, and I had not got mine yet." + +"But how about Mr. Hosmer Angel? Did he make no attempt to see +you?" + +"Well, father was going off to France again in a week, and Hosmer +wrote and said that it would be safer and better not to see each +other until he had gone. We could write in the meantime, and he +used to write every day. I took the letters in in the morning, so +there was no need for father to know." + +"Were you engaged to the gentleman at this time?" + +"Oh, yes, Mr. Holmes. We were engaged after the first walk that +we took. Hosmer--Mr. Angel--was a cashier in an office in +Leadenhall Street--and--" + +"What office?" + +"That's the worst of it, Mr. Holmes, I don't know." + +"Where did he live, then?" + +"He slept on the premises." + +"And you don't know his address?" + +"No--except that it was Leadenhall Street." + +"Where did you address your letters, then?" + +"To the Leadenhall Street Post Office, to be left till called +for. He said that if they were sent to the office he would be +chaffed by all the other clerks about having letters from a lady, +so I offered to typewrite them, like he did his, but he wouldn't +have that, for he said that when I wrote them they seemed to come +from me, but when they were typewritten he always felt that the +machine had come between us. That will just show you how fond he +was of me, Mr. Holmes, and the little things that he would think +of." + +"It was most suggestive," said Holmes. "It has long been an axiom +of mine that the little things are infinitely the most important. +Can you remember any other little things about Mr. Hosmer Angel?" + +"He was a very shy man, Mr. Holmes. He would rather walk with me +in the evening than in the daylight, for he said that he hated to +be conspicuous. Very retiring and gentlemanly he was. Even his +voice was gentle. He'd had the quinsy and swollen glands when he +was young, he told me, and it had left him with a weak throat, +and a hesitating, whispering fashion of speech. He was always +well dressed, very neat and plain, but his eyes were weak, just +as mine are, and he wore tinted glasses against the glare." + +"Well, and what happened when Mr. Windibank, your stepfather, +returned to France?" + +"Mr. Hosmer Angel came to the house again and proposed that we +should marry before father came back. He was in dreadful earnest +and made me swear, with my hands on the Testament, that whatever +happened I would always be true to him. Mother said he was quite +right to make me swear, and that it was a sign of his passion. +Mother was all in his favour from the first and was even fonder +of him than I was. Then, when they talked of marrying within the +week, I began to ask about father; but they both said never to +mind about father, but just to tell him afterwards, and mother +said she would make it all right with him. I didn't quite like +that, Mr. Holmes. It seemed funny that I should ask his leave, as +he was only a few years older than me; but I didn't want to do +anything on the sly, so I wrote to father at Bordeaux, where the +company has its French offices, but the letter came back to me on +the very morning of the wedding." + +"It missed him, then?" + +"Yes, sir; for he had started to England just before it arrived." + +"Ha! that was unfortunate. Your wedding was arranged, then, for +the Friday. Was it to be in church?" + +"Yes, sir, but very quietly. It was to be at St. Saviour's, near +King's Cross, and we were to have breakfast afterwards at the St. +Pancras Hotel. Hosmer came for us in a hansom, but as there were +two of us he put us both into it and stepped himself into a +four-wheeler, which happened to be the only other cab in the +street. We got to the church first, and when the four-wheeler +drove up we waited for him to step out, but he never did, and +when the cabman got down from the box and looked there was no one +there! The cabman said that he could not imagine what had become +of him, for he had seen him get in with his own eyes. That was +last Friday, Mr. Holmes, and I have never seen or heard anything +since then to throw any light upon what became of him." + +"It seems to me that you have been very shamefully treated," said +Holmes. + +"Oh, no, sir! He was too good and kind to leave me so. Why, all +the morning he was saying to me that, whatever happened, I was to +be true; and that even if something quite unforeseen occurred to +separate us, I was always to remember that I was pledged to him, +and that he would claim his pledge sooner or later. It seemed +strange talk for a wedding-morning, but what has happened since +gives a meaning to it." + +"Most certainly it does. Your own opinion is, then, that some +unforeseen catastrophe has occurred to him?" + +"Yes, sir. I believe that he foresaw some danger, or else he +would not have talked so. And then I think that what he foresaw +happened." + +"But you have no notion as to what it could have been?" + +"None." + +"One more question. How did your mother take the matter?" + +"She was angry, and said that I was never to speak of the matter +again." + +"And your father? Did you tell him?" + +"Yes; and he seemed to think, with me, that something had +happened, and that I should hear of Hosmer again. As he said, +what interest could anyone have in bringing me to the doors of +the church, and then leaving me? Now, if he had borrowed my +money, or if he had married me and got my money settled on him, +there might be some reason, but Hosmer was very independent about +money and never would look at a shilling of mine. And yet, what +could have happened? And why could he not write? Oh, it drives me +half-mad to think of it, and I can't sleep a wink at night." She +pulled a little handkerchief out of her muff and began to sob +heavily into it. + +"I shall glance into the case for you," said Holmes, rising, "and +I have no doubt that we shall reach some definite result. Let the +weight of the matter rest upon me now, and do not let your mind +dwell upon it further. Above all, try to let Mr. Hosmer Angel +vanish from your memory, as he has done from your life." + +"Then you don't think I'll see him again?" + +"I fear not." + +"Then what has happened to him?" + +"You will leave that question in my hands. I should like an +accurate description of him and any letters of his which you can +spare." + +"I advertised for him in last Saturday's Chronicle," said she. +"Here is the slip and here are four letters from him." + +"Thank you. And your address?" + +"No. 31 Lyon Place, Camberwell." + +"Mr. Angel's address you never had, I understand. Where is your +father's place of business?" + +"He travels for Westhouse & Marbank, the great claret importers +of Fenchurch Street." + +"Thank you. You have made your statement very clearly. You will +leave the papers here, and remember the advice which I have given +you. Let the whole incident be a sealed book, and do not allow it +to affect your life." + +"You are very kind, Mr. Holmes, but I cannot do that. I shall be +true to Hosmer. He shall find me ready when he comes back." + +For all the preposterous hat and the vacuous face, there was +something noble in the simple faith of our visitor which +compelled our respect. She laid her little bundle of papers upon +the table and went her way, with a promise to come again whenever +she might be summoned. + +Sherlock Holmes sat silent for a few minutes with his fingertips +still pressed together, his legs stretched out in front of him, +and his gaze directed upward to the ceiling. Then he took down +from the rack the old and oily clay pipe, which was to him as a +counsellor, and, having lit it, he leaned back in his chair, with +the thick blue cloud-wreaths spinning up from him, and a look of +infinite languor in his face. + +"Quite an interesting study, that maiden," he observed. "I found +her more interesting than her little problem, which, by the way, +is rather a trite one. You will find parallel cases, if you +consult my index, in Andover in '77, and there was something of +the sort at The Hague last year. Old as is the idea, however, +there were one or two details which were new to me. But the +maiden herself was most instructive." + +"You appeared to read a good deal upon her which was quite +invisible to me," I remarked. + +"Not invisible but unnoticed, Watson. You did not know where to +look, and so you missed all that was important. I can never bring +you to realise the importance of sleeves, the suggestiveness of +thumb-nails, or the great issues that may hang from a boot-lace. +Now, what did you gather from that woman's appearance? Describe +it." + +"Well, she had a slate-coloured, broad-brimmed straw hat, with a +feather of a brickish red. Her jacket was black, with black beads +sewn upon it, and a fringe of little black jet ornaments. Her +dress was brown, rather darker than coffee colour, with a little +purple plush at the neck and sleeves. Her gloves were greyish and +were worn through at the right forefinger. Her boots I didn't +observe. She had small round, hanging gold earrings, and a +general air of being fairly well-to-do in a vulgar, comfortable, +easy-going way." + +Sherlock Holmes clapped his hands softly together and chuckled. + +"'Pon my word, Watson, you are coming along wonderfully. You have +really done very well indeed. It is true that you have missed +everything of importance, but you have hit upon the method, and +you have a quick eye for colour. Never trust to general +impressions, my boy, but concentrate yourself upon details. My +first glance is always at a woman's sleeve. In a man it is +perhaps better first to take the knee of the trouser. As you +observe, this woman had plush upon her sleeves, which is a most +useful material for showing traces. The double line a little +above the wrist, where the typewritist presses against the table, +was beautifully defined. The sewing-machine, of the hand type, +leaves a similar mark, but only on the left arm, and on the side +of it farthest from the thumb, instead of being right across the +broadest part, as this was. I then glanced at her face, and, +observing the dint of a pince-nez at either side of her nose, I +ventured a remark upon short sight and typewriting, which seemed +to surprise her." + +"It surprised me." + +"But, surely, it was obvious. I was then much surprised and +interested on glancing down to observe that, though the boots +which she was wearing were not unlike each other, they were +really odd ones; the one having a slightly decorated toe-cap, and +the other a plain one. One was buttoned only in the two lower +buttons out of five, and the other at the first, third, and +fifth. Now, when you see that a young lady, otherwise neatly +dressed, has come away from home with odd boots, half-buttoned, +it is no great deduction to say that she came away in a hurry." + +"And what else?" I asked, keenly interested, as I always was, by +my friend's incisive reasoning. + +"I noted, in passing, that she had written a note before leaving +home but after being fully dressed. You observed that her right +glove was torn at the forefinger, but you did not apparently see +that both glove and finger were stained with violet ink. She had +written in a hurry and dipped her pen too deep. It must have been +this morning, or the mark would not remain clear upon the finger. +All this is amusing, though rather elementary, but I must go back +to business, Watson. Would you mind reading me the advertised +description of Mr. Hosmer Angel?" + +I held the little printed slip to the light. + +"Missing," it said, "on the morning of the fourteenth, a gentleman +named Hosmer Angel. About five ft. seven in. in height; +strongly built, sallow complexion, black hair, a little bald in +the centre, bushy, black side-whiskers and moustache; tinted +glasses, slight infirmity of speech. Was dressed, when last seen, +in black frock-coat faced with silk, black waistcoat, gold Albert +chain, and grey Harris tweed trousers, with brown gaiters over +elastic-sided boots. Known to have been employed in an office in +Leadenhall Street. Anybody bringing--" + +"That will do," said Holmes. "As to the letters," he continued, +glancing over them, "they are very commonplace. Absolutely no +clue in them to Mr. Angel, save that he quotes Balzac once. There +is one remarkable point, however, which will no doubt strike +you." + +"They are typewritten," I remarked. + +"Not only that, but the signature is typewritten. Look at the +neat little 'Hosmer Angel' at the bottom. There is a date, you +see, but no superscription except Leadenhall Street, which is +rather vague. The point about the signature is very suggestive--in +fact, we may call it conclusive." + +"Of what?" + +"My dear fellow, is it possible you do not see how strongly it +bears upon the case?" + +"I cannot say that I do unless it were that he wished to be able +to deny his signature if an action for breach of promise were +instituted." + +"No, that was not the point. However, I shall write two letters, +which should settle the matter. One is to a firm in the City, the +other is to the young lady's stepfather, Mr. Windibank, asking +him whether he could meet us here at six o'clock tomorrow +evening. It is just as well that we should do business with the +male relatives. And now, Doctor, we can do nothing until the +answers to those letters come, so we may put our little problem +upon the shelf for the interim." + +I had had so many reasons to believe in my friend's subtle powers +of reasoning and extraordinary energy in action that I felt that +he must have some solid grounds for the assured and easy +demeanour with which he treated the singular mystery which he had +been called upon to fathom. Once only had I known him to fail, in +the case of the King of Bohemia and of the Irene Adler +photograph; but when I looked back to the weird business of the +Sign of Four, and the extraordinary circumstances connected with +the Study in Scarlet, I felt that it would be a strange tangle +indeed which he could not unravel. + +I left him then, still puffing at his black clay pipe, with the +conviction that when I came again on the next evening I would +find that he held in his hands all the clues which would lead up +to the identity of the disappearing bridegroom of Miss Mary +Sutherland. + +A professional case of great gravity was engaging my own +attention at the time, and the whole of next day I was busy at +the bedside of the sufferer. It was not until close upon six +o'clock that I found myself free and was able to spring into a +hansom and drive to Baker Street, half afraid that I might be too +late to assist at the dénouement of the little mystery. I found +Sherlock Holmes alone, however, half asleep, with his long, thin +form curled up in the recesses of his armchair. A formidable +array of bottles and test-tubes, with the pungent cleanly smell +of hydrochloric acid, told me that he had spent his day in the +chemical work which was so dear to him. + +"Well, have you solved it?" I asked as I entered. + +"Yes. It was the bisulphate of baryta." + +"No, no, the mystery!" I cried. + +"Oh, that! I thought of the salt that I have been working upon. +There was never any mystery in the matter, though, as I said +yesterday, some of the details are of interest. The only drawback +is that there is no law, I fear, that can touch the scoundrel." + +"Who was he, then, and what was his object in deserting Miss +Sutherland?" + +The question was hardly out of my mouth, and Holmes had not yet +opened his lips to reply, when we heard a heavy footfall in the +passage and a tap at the door. + +"This is the girl's stepfather, Mr. James Windibank," said +Holmes. "He has written to me to say that he would be here at +six. Come in!" + +The man who entered was a sturdy, middle-sized fellow, some +thirty years of age, clean-shaven, and sallow-skinned, with a +bland, insinuating manner, and a pair of wonderfully sharp and +penetrating grey eyes. He shot a questioning glance at each of +us, placed his shiny top-hat upon the sideboard, and with a +slight bow sidled down into the nearest chair. + +"Good-evening, Mr. James Windibank," said Holmes. "I think that +this typewritten letter is from you, in which you made an +appointment with me for six o'clock?" + +"Yes, sir. I am afraid that I am a little late, but I am not +quite my own master, you know. I am sorry that Miss Sutherland +has troubled you about this little matter, for I think it is far +better not to wash linen of the sort in public. It was quite +against my wishes that she came, but she is a very excitable, +impulsive girl, as you may have noticed, and she is not easily +controlled when she has made up her mind on a point. Of course, I +did not mind you so much, as you are not connected with the +official police, but it is not pleasant to have a family +misfortune like this noised abroad. Besides, it is a useless +expense, for how could you possibly find this Hosmer Angel?" + +"On the contrary," said Holmes quietly; "I have every reason to +believe that I will succeed in discovering Mr. Hosmer Angel." + +Mr. Windibank gave a violent start and dropped his gloves. "I am +delighted to hear it," he said. + +"It is a curious thing," remarked Holmes, "that a typewriter has +really quite as much individuality as a man's handwriting. Unless +they are quite new, no two of them write exactly alike. Some +letters get more worn than others, and some wear only on one +side. Now, you remark in this note of yours, Mr. Windibank, that +in every case there is some little slurring over of the 'e,' and +a slight defect in the tail of the 'r.' There are fourteen other +characteristics, but those are the more obvious." + +"We do all our correspondence with this machine at the office, +and no doubt it is a little worn," our visitor answered, glancing +keenly at Holmes with his bright little eyes. + +"And now I will show you what is really a very interesting study, +Mr. Windibank," Holmes continued. "I think of writing another +little monograph some of these days on the typewriter and its +relation to crime. It is a subject to which I have devoted some +little attention. I have here four letters which purport to come +from the missing man. They are all typewritten. In each case, not +only are the 'e's' slurred and the 'r's' tailless, but you will +observe, if you care to use my magnifying lens, that the fourteen +other characteristics to which I have alluded are there as well." + +Mr. Windibank sprang out of his chair and picked up his hat. "I +cannot waste time over this sort of fantastic talk, Mr. Holmes," +he said. "If you can catch the man, catch him, and let me know +when you have done it." + +"Certainly," said Holmes, stepping over and turning the key in +the door. "I let you know, then, that I have caught him!" + +"What! where?" shouted Mr. Windibank, turning white to his lips +and glancing about him like a rat in a trap. + +"Oh, it won't do--really it won't," said Holmes suavely. "There +is no possible getting out of it, Mr. Windibank. It is quite too +transparent, and it was a very bad compliment when you said that +it was impossible for me to solve so simple a question. That's +right! Sit down and let us talk it over." + +Our visitor collapsed into a chair, with a ghastly face and a +glitter of moisture on his brow. "It--it's not actionable," he +stammered. + +"I am very much afraid that it is not. But between ourselves, +Windibank, it was as cruel and selfish and heartless a trick in a +petty way as ever came before me. Now, let me just run over the +course of events, and you will contradict me if I go wrong." + +The man sat huddled up in his chair, with his head sunk upon his +breast, like one who is utterly crushed. Holmes stuck his feet up +on the corner of the mantelpiece and, leaning back with his hands +in his pockets, began talking, rather to himself, as it seemed, +than to us. + +"The man married a woman very much older than himself for her +money," said he, "and he enjoyed the use of the money of the +daughter as long as she lived with them. It was a considerable +sum, for people in their position, and the loss of it would have +made a serious difference. It was worth an effort to preserve it. +The daughter was of a good, amiable disposition, but affectionate +and warm-hearted in her ways, so that it was evident that with +her fair personal advantages, and her little income, she would +not be allowed to remain single long. Now her marriage would +mean, of course, the loss of a hundred a year, so what does her +stepfather do to prevent it? He takes the obvious course of +keeping her at home and forbidding her to seek the company of +people of her own age. But soon he found that that would not +answer forever. She became restive, insisted upon her rights, and +finally announced her positive intention of going to a certain +ball. What does her clever stepfather do then? He conceives an +idea more creditable to his head than to his heart. With the +connivance and assistance of his wife he disguised himself, +covered those keen eyes with tinted glasses, masked the face with +a moustache and a pair of bushy whiskers, sunk that clear voice +into an insinuating whisper, and doubly secure on account of the +girl's short sight, he appears as Mr. Hosmer Angel, and keeps off +other lovers by making love himself." + +"It was only a joke at first," groaned our visitor. "We never +thought that she would have been so carried away." + +"Very likely not. However that may be, the young lady was very +decidedly carried away, and, having quite made up her mind that +her stepfather was in France, the suspicion of treachery never +for an instant entered her mind. She was flattered by the +gentleman's attentions, and the effect was increased by the +loudly expressed admiration of her mother. Then Mr. Angel began +to call, for it was obvious that the matter should be pushed as +far as it would go if a real effect were to be produced. There +were meetings, and an engagement, which would finally secure the +girl's affections from turning towards anyone else. But the +deception could not be kept up forever. These pretended journeys +to France were rather cumbrous. The thing to do was clearly to +bring the business to an end in such a dramatic manner that it +would leave a permanent impression upon the young lady's mind and +prevent her from looking upon any other suitor for some time to +come. Hence those vows of fidelity exacted upon a Testament, and +hence also the allusions to a possibility of something happening +on the very morning of the wedding. James Windibank wished Miss +Sutherland to be so bound to Hosmer Angel, and so uncertain as to +his fate, that for ten years to come, at any rate, she would not +listen to another man. As far as the church door he brought her, +and then, as he could go no farther, he conveniently vanished +away by the old trick of stepping in at one door of a +four-wheeler and out at the other. I think that was the chain of +events, Mr. Windibank!" + +Our visitor had recovered something of his assurance while Holmes +had been talking, and he rose from his chair now with a cold +sneer upon his pale face. + +"It may be so, or it may not, Mr. Holmes," said he, "but if you +are so very sharp you ought to be sharp enough to know that it is +you who are breaking the law now, and not me. I have done nothing +actionable from the first, but as long as you keep that door +locked you lay yourself open to an action for assault and illegal +constraint." + +"The law cannot, as you say, touch you," said Holmes, unlocking +and throwing open the door, "yet there never was a man who +deserved punishment more. If the young lady has a brother or a +friend, he ought to lay a whip across your shoulders. By Jove!" +he continued, flushing up at the sight of the bitter sneer upon +the man's face, "it is not part of my duties to my client, but +here's a hunting crop handy, and I think I shall just treat +myself to--" He took two swift steps to the whip, but before he +could grasp it there was a wild clatter of steps upon the stairs, +the heavy hall door banged, and from the window we could see Mr. +James Windibank running at the top of his speed down the road. + +"There's a cold-blooded scoundrel!" said Holmes, laughing, as he +threw himself down into his chair once more. "That fellow will +rise from crime to crime until he does something very bad, and +ends on a gallows. The case has, in some respects, been not +entirely devoid of interest." + +"I cannot now entirely see all the steps of your reasoning," I +remarked. + +"Well, of course it was obvious from the first that this Mr. +Hosmer Angel must have some strong object for his curious +conduct, and it was equally clear that the only man who really +profited by the incident, as far as we could see, was the +stepfather. Then the fact that the two men were never together, +but that the one always appeared when the other was away, was +suggestive. So were the tinted spectacles and the curious voice, +which both hinted at a disguise, as did the bushy whiskers. My +suspicions were all confirmed by his peculiar action in +typewriting his signature, which, of course, inferred that his +handwriting was so familiar to her that she would recognise even +the smallest sample of it. You see all these isolated facts, +together with many minor ones, all pointed in the same +direction." + +"And how did you verify them?" + +"Having once spotted my man, it was easy to get corroboration. I +knew the firm for which this man worked. Having taken the printed +description. I eliminated everything from it which could be the +result of a disguise--the whiskers, the glasses, the voice, and I +sent it to the firm, with a request that they would inform me +whether it answered to the description of any of their +travellers. I had already noticed the peculiarities of the +typewriter, and I wrote to the man himself at his business +address asking him if he would come here. As I expected, his +reply was typewritten and revealed the same trivial but +characteristic defects. The same post brought me a letter from +Westhouse & Marbank, of Fenchurch Street, to say that the +description tallied in every respect with that of their employé, +James Windibank. Voilà tout!" + +"And Miss Sutherland?" + +"If I tell her she will not believe me. You may remember the old +Persian saying, 'There is danger for him who taketh the tiger +cub, and danger also for whoso snatches a delusion from a woman.' +There is as much sense in Hafiz as in Horace, and as much +knowledge of the world." + + + +ADVENTURE IV. THE BOSCOMBE VALLEY MYSTERY + +We were seated at breakfast one morning, my wife and I, when the +maid brought in a telegram. It was from Sherlock Holmes and ran +in this way: + +"Have you a couple of days to spare? Have just been wired for from +the west of England in connection with Boscombe Valley tragedy. +Shall be glad if you will come with me. Air and scenery perfect. +Leave Paddington by the 11:15." + +"What do you say, dear?" said my wife, looking across at me. +"Will you go?" + +"I really don't know what to say. I have a fairly long list at +present." + +"Oh, Anstruther would do your work for you. You have been looking +a little pale lately. I think that the change would do you good, +and you are always so interested in Mr. Sherlock Holmes' cases." + +"I should be ungrateful if I were not, seeing what I gained +through one of them," I answered. "But if I am to go, I must pack +at once, for I have only half an hour." + +My experience of camp life in Afghanistan had at least had the +effect of making me a prompt and ready traveller. My wants were +few and simple, so that in less than the time stated I was in a +cab with my valise, rattling away to Paddington Station. Sherlock +Holmes was pacing up and down the platform, his tall, gaunt +figure made even gaunter and taller by his long grey +travelling-cloak and close-fitting cloth cap. + +"It is really very good of you to come, Watson," said he. "It +makes a considerable difference to me, having someone with me on +whom I can thoroughly rely. Local aid is always either worthless +or else biassed. If you will keep the two corner seats I shall +get the tickets." + +We had the carriage to ourselves save for an immense litter of +papers which Holmes had brought with him. Among these he rummaged +and read, with intervals of note-taking and of meditation, until +we were past Reading. Then he suddenly rolled them all into a +gigantic ball and tossed them up onto the rack. + +"Have you heard anything of the case?" he asked. + +"Not a word. I have not seen a paper for some days." + +"The London press has not had very full accounts. I have just +been looking through all the recent papers in order to master the +particulars. It seems, from what I gather, to be one of those +simple cases which are so extremely difficult." + +"That sounds a little paradoxical." + +"But it is profoundly true. Singularity is almost invariably a +clue. The more featureless and commonplace a crime is, the more +difficult it is to bring it home. In this case, however, they +have established a very serious case against the son of the +murdered man." + +"It is a murder, then?" + +"Well, it is conjectured to be so. I shall take nothing for +granted until I have the opportunity of looking personally into +it. I will explain the state of things to you, as far as I have +been able to understand it, in a very few words. + +"Boscombe Valley is a country district not very far from Ross, in +Herefordshire. The largest landed proprietor in that part is a +Mr. John Turner, who made his money in Australia and returned +some years ago to the old country. One of the farms which he +held, that of Hatherley, was let to Mr. Charles McCarthy, who was +also an ex-Australian. The men had known each other in the +colonies, so that it was not unnatural that when they came to +settle down they should do so as near each other as possible. +Turner was apparently the richer man, so McCarthy became his +tenant but still remained, it seems, upon terms of perfect +equality, as they were frequently together. McCarthy had one son, +a lad of eighteen, and Turner had an only daughter of the same +age, but neither of them had wives living. They appear to have +avoided the society of the neighbouring English families and to +have led retired lives, though both the McCarthys were fond of +sport and were frequently seen at the race-meetings of the +neighbourhood. McCarthy kept two servants--a man and a girl. +Turner had a considerable household, some half-dozen at the +least. That is as much as I have been able to gather about the +families. Now for the facts. + +"On June 3rd, that is, on Monday last, McCarthy left his house at +Hatherley about three in the afternoon and walked down to the +Boscombe Pool, which is a small lake formed by the spreading out +of the stream which runs down the Boscombe Valley. He had been +out with his serving-man in the morning at Ross, and he had told +the man that he must hurry, as he had an appointment of +importance to keep at three. From that appointment he never came +back alive. + +"From Hatherley Farm-house to the Boscombe Pool is a quarter of a +mile, and two people saw him as he passed over this ground. One +was an old woman, whose name is not mentioned, and the other was +William Crowder, a game-keeper in the employ of Mr. Turner. Both +these witnesses depose that Mr. McCarthy was walking alone. The +game-keeper adds that within a few minutes of his seeing Mr. +McCarthy pass he had seen his son, Mr. James McCarthy, going the +same way with a gun under his arm. To the best of his belief, the +father was actually in sight at the time, and the son was +following him. He thought no more of the matter until he heard in +the evening of the tragedy that had occurred. + +"The two McCarthys were seen after the time when William Crowder, +the game-keeper, lost sight of them. The Boscombe Pool is thickly +wooded round, with just a fringe of grass and of reeds round the +edge. A girl of fourteen, Patience Moran, who is the daughter of +the lodge-keeper of the Boscombe Valley estate, was in one of the +woods picking flowers. She states that while she was there she +saw, at the border of the wood and close by the lake, Mr. +McCarthy and his son, and that they appeared to be having a +violent quarrel. She heard Mr. McCarthy the elder using very +strong language to his son, and she saw the latter raise up his +hand as if to strike his father. She was so frightened by their +violence that she ran away and told her mother when she reached +home that she had left the two McCarthys quarrelling near +Boscombe Pool, and that she was afraid that they were going to +fight. She had hardly said the words when young Mr. McCarthy came +running up to the lodge to say that he had found his father dead +in the wood, and to ask for the help of the lodge-keeper. He was +much excited, without either his gun or his hat, and his right +hand and sleeve were observed to be stained with fresh blood. On +following him they found the dead body stretched out upon the +grass beside the pool. The head had been beaten in by repeated +blows of some heavy and blunt weapon. The injuries were such as +might very well have been inflicted by the butt-end of his son's +gun, which was found lying on the grass within a few paces of the +body. Under these circumstances the young man was instantly +arrested, and a verdict of 'wilful murder' having been returned +at the inquest on Tuesday, he was on Wednesday brought before the +magistrates at Ross, who have referred the case to the next +Assizes. Those are the main facts of the case as they came out +before the coroner and the police-court." + +"I could hardly imagine a more damning case," I remarked. "If +ever circumstantial evidence pointed to a criminal it does so +here." + +"Circumstantial evidence is a very tricky thing," answered Holmes +thoughtfully. "It may seem to point very straight to one thing, +but if you shift your own point of view a little, you may find it +pointing in an equally uncompromising manner to something +entirely different. It must be confessed, however, that the case +looks exceedingly grave against the young man, and it is very +possible that he is indeed the culprit. There are several people +in the neighbourhood, however, and among them Miss Turner, the +daughter of the neighbouring landowner, who believe in his +innocence, and who have retained Lestrade, whom you may recollect +in connection with the Study in Scarlet, to work out the case in +his interest. Lestrade, being rather puzzled, has referred the +case to me, and hence it is that two middle-aged gentlemen are +flying westward at fifty miles an hour instead of quietly +digesting their breakfasts at home." + +"I am afraid," said I, "that the facts are so obvious that you +will find little credit to be gained out of this case." + +"There is nothing more deceptive than an obvious fact," he +answered, laughing. "Besides, we may chance to hit upon some +other obvious facts which may have been by no means obvious to +Mr. Lestrade. You know me too well to think that I am boasting +when I say that I shall either confirm or destroy his theory by +means which he is quite incapable of employing, or even of +understanding. To take the first example to hand, I very clearly +perceive that in your bedroom the window is upon the right-hand +side, and yet I question whether Mr. Lestrade would have noted +even so self-evident a thing as that." + +"How on earth--" + +"My dear fellow, I know you well. I know the military neatness +which characterises you. You shave every morning, and in this +season you shave by the sunlight; but since your shaving is less +and less complete as we get farther back on the left side, until +it becomes positively slovenly as we get round the angle of the +jaw, it is surely very clear that that side is less illuminated +than the other. I could not imagine a man of your habits looking +at himself in an equal light and being satisfied with such a +result. I only quote this as a trivial example of observation and +inference. Therein lies my métier, and it is just possible that +it may be of some service in the investigation which lies before +us. There are one or two minor points which were brought out in +the inquest, and which are worth considering." + +"What are they?" + +"It appears that his arrest did not take place at once, but after +the return to Hatherley Farm. On the inspector of constabulary +informing him that he was a prisoner, he remarked that he was not +surprised to hear it, and that it was no more than his deserts. +This observation of his had the natural effect of removing any +traces of doubt which might have remained in the minds of the +coroner's jury." + +"It was a confession," I ejaculated. + +"No, for it was followed by a protestation of innocence." + +"Coming on the top of such a damning series of events, it was at +least a most suspicious remark." + +"On the contrary," said Holmes, "it is the brightest rift which I +can at present see in the clouds. However innocent he might be, +he could not be such an absolute imbecile as not to see that the +circumstances were very black against him. Had he appeared +surprised at his own arrest, or feigned indignation at it, I +should have looked upon it as highly suspicious, because such +surprise or anger would not be natural under the circumstances, +and yet might appear to be the best policy to a scheming man. His +frank acceptance of the situation marks him as either an innocent +man, or else as a man of considerable self-restraint and +firmness. As to his remark about his deserts, it was also not +unnatural if you consider that he stood beside the dead body of +his father, and that there is no doubt that he had that very day +so far forgotten his filial duty as to bandy words with him, and +even, according to the little girl whose evidence is so +important, to raise his hand as if to strike him. The +self-reproach and contrition which are displayed in his remark +appear to me to be the signs of a healthy mind rather than of a +guilty one." + +I shook my head. "Many men have been hanged on far slighter +evidence," I remarked. + +"So they have. And many men have been wrongfully hanged." + +"What is the young man's own account of the matter?" + +"It is, I am afraid, not very encouraging to his supporters, +though there are one or two points in it which are suggestive. +You will find it here, and may read it for yourself." + +He picked out from his bundle a copy of the local Herefordshire +paper, and having turned down the sheet he pointed out the +paragraph in which the unfortunate young man had given his own +statement of what had occurred. I settled myself down in the +corner of the carriage and read it very carefully. It ran in this +way: + +"Mr. James McCarthy, the only son of the deceased, was then called +and gave evidence as follows: 'I had been away from home for +three days at Bristol, and had only just returned upon the +morning of last Monday, the 3rd. My father was absent from home at +the time of my arrival, and I was informed by the maid that he +had driven over to Ross with John Cobb, the groom. Shortly after +my return I heard the wheels of his trap in the yard, and, +looking out of my window, I saw him get out and walk rapidly out +of the yard, though I was not aware in which direction he was +going. I then took my gun and strolled out in the direction of +the Boscombe Pool, with the intention of visiting the rabbit +warren which is upon the other side. On my way I saw William +Crowder, the game-keeper, as he had stated in his evidence; but +he is mistaken in thinking that I was following my father. I had +no idea that he was in front of me. When about a hundred yards +from the pool I heard a cry of "Cooee!" which was a usual signal +between my father and myself. I then hurried forward, and found +him standing by the pool. He appeared to be much surprised at +seeing me and asked me rather roughly what I was doing there. A +conversation ensued which led to high words and almost to blows, +for my father was a man of a very violent temper. Seeing that his +passion was becoming ungovernable, I left him and returned +towards Hatherley Farm. I had not gone more than 150 yards, +however, when I heard a hideous outcry behind me, which caused me +to run back again. I found my father expiring upon the ground, +with his head terribly injured. I dropped my gun and held him in +my arms, but he almost instantly expired. I knelt beside him for +some minutes, and then made my way to Mr. Turner's lodge-keeper, +his house being the nearest, to ask for assistance. I saw no one +near my father when I returned, and I have no idea how he came by +his injuries. He was not a popular man, being somewhat cold and +forbidding in his manners, but he had, as far as I know, no +active enemies. I know nothing further of the matter.' + +"The Coroner: Did your father make any statement to you before +he died? + +"Witness: He mumbled a few words, but I could only catch some +allusion to a rat. + +"The Coroner: What did you understand by that? + +"Witness: It conveyed no meaning to me. I thought that he was +delirious. + +"The Coroner: What was the point upon which you and your father +had this final quarrel? + +"Witness: I should prefer not to answer. + +"The Coroner: I am afraid that I must press it. + +"Witness: It is really impossible for me to tell you. I can +assure you that it has nothing to do with the sad tragedy which +followed. + +"The Coroner: That is for the court to decide. I need not point +out to you that your refusal to answer will prejudice your case +considerably in any future proceedings which may arise. + +"Witness: I must still refuse. + +"The Coroner: I understand that the cry of 'Cooee' was a common +signal between you and your father? + +"Witness: It was. + +"The Coroner: How was it, then, that he uttered it before he saw +you, and before he even knew that you had returned from Bristol? + +"Witness (with considerable confusion): I do not know. + +"A Juryman: Did you see nothing which aroused your suspicions +when you returned on hearing the cry and found your father +fatally injured? + +"Witness: Nothing definite. + +"The Coroner: What do you mean? + +"Witness: I was so disturbed and excited as I rushed out into +the open, that I could think of nothing except of my father. Yet +I have a vague impression that as I ran forward something lay +upon the ground to the left of me. It seemed to me to be +something grey in colour, a coat of some sort, or a plaid perhaps. +When I rose from my father I looked round for it, but it was +gone. + +"'Do you mean that it disappeared before you went for help?' + +"'Yes, it was gone.' + +"'You cannot say what it was?' + +"'No, I had a feeling something was there.' + +"'How far from the body?' + +"'A dozen yards or so.' + +"'And how far from the edge of the wood?' + +"'About the same.' + +"'Then if it was removed it was while you were within a dozen +yards of it?' + +"'Yes, but with my back towards it.' + +"This concluded the examination of the witness." + +"I see," said I as I glanced down the column, "that the coroner +in his concluding remarks was rather severe upon young McCarthy. +He calls attention, and with reason, to the discrepancy about his +father having signalled to him before seeing him, also to his +refusal to give details of his conversation with his father, and +his singular account of his father's dying words. They are all, +as he remarks, very much against the son." + +Holmes laughed softly to himself and stretched himself out upon +the cushioned seat. "Both you and the coroner have been at some +pains," said he, "to single out the very strongest points in the +young man's favour. Don't you see that you alternately give him +credit for having too much imagination and too little? Too +little, if he could not invent a cause of quarrel which would +give him the sympathy of the jury; too much, if he evolved from +his own inner consciousness anything so outré as a dying +reference to a rat, and the incident of the vanishing cloth. No, +sir, I shall approach this case from the point of view that what +this young man says is true, and we shall see whither that +hypothesis will lead us. And now here is my pocket Petrarch, and +not another word shall I say of this case until we are on the +scene of action. We lunch at Swindon, and I see that we shall be +there in twenty minutes." + +It was nearly four o'clock when we at last, after passing through +the beautiful Stroud Valley, and over the broad gleaming Severn, +found ourselves at the pretty little country-town of Ross. A +lean, ferret-like man, furtive and sly-looking, was waiting for +us upon the platform. In spite of the light brown dustcoat and +leather-leggings which he wore in deference to his rustic +surroundings, I had no difficulty in recognising Lestrade, of +Scotland Yard. With him we drove to the Hereford Arms where a +room had already been engaged for us. + +"I have ordered a carriage," said Lestrade as we sat over a cup +of tea. "I knew your energetic nature, and that you would not be +happy until you had been on the scene of the crime." + +"It was very nice and complimentary of you," Holmes answered. "It +is entirely a question of barometric pressure." + +Lestrade looked startled. "I do not quite follow," he said. + +"How is the glass? Twenty-nine, I see. No wind, and not a cloud +in the sky. I have a caseful of cigarettes here which need +smoking, and the sofa is very much superior to the usual country +hotel abomination. I do not think that it is probable that I +shall use the carriage to-night." + +Lestrade laughed indulgently. "You have, no doubt, already formed +your conclusions from the newspapers," he said. "The case is as +plain as a pikestaff, and the more one goes into it the plainer +it becomes. Still, of course, one can't refuse a lady, and such a +very positive one, too. She has heard of you, and would have your +opinion, though I repeatedly told her that there was nothing +which you could do which I had not already done. Why, bless my +soul! here is her carriage at the door." + +He had hardly spoken before there rushed into the room one of the +most lovely young women that I have ever seen in my life. Her +violet eyes shining, her lips parted, a pink flush upon her +cheeks, all thought of her natural reserve lost in her +overpowering excitement and concern. + +"Oh, Mr. Sherlock Holmes!" she cried, glancing from one to the +other of us, and finally, with a woman's quick intuition, +fastening upon my companion, "I am so glad that you have come. I +have driven down to tell you so. I know that James didn't do it. +I know it, and I want you to start upon your work knowing it, +too. Never let yourself doubt upon that point. We have known each +other since we were little children, and I know his faults as no +one else does; but he is too tender-hearted to hurt a fly. Such a +charge is absurd to anyone who really knows him." + +"I hope we may clear him, Miss Turner," said Sherlock Holmes. +"You may rely upon my doing all that I can." + +"But you have read the evidence. You have formed some conclusion? +Do you not see some loophole, some flaw? Do you not yourself +think that he is innocent?" + +"I think that it is very probable." + +"There, now!" she cried, throwing back her head and looking +defiantly at Lestrade. "You hear! He gives me hopes." + +Lestrade shrugged his shoulders. "I am afraid that my colleague +has been a little quick in forming his conclusions," he said. + +"But he is right. Oh! I know that he is right. James never did +it. And about his quarrel with his father, I am sure that the +reason why he would not speak about it to the coroner was because +I was concerned in it." + +"In what way?" asked Holmes. + +"It is no time for me to hide anything. James and his father had +many disagreements about me. Mr. McCarthy was very anxious that +there should be a marriage between us. James and I have always +loved each other as brother and sister; but of course he is young +and has seen very little of life yet, and--and--well, he +naturally did not wish to do anything like that yet. So there +were quarrels, and this, I am sure, was one of them." + +"And your father?" asked Holmes. "Was he in favour of such a +union?" + +"No, he was averse to it also. No one but Mr. McCarthy was in +favour of it." A quick blush passed over her fresh young face as +Holmes shot one of his keen, questioning glances at her. + +"Thank you for this information," said he. "May I see your father +if I call to-morrow?" + +"I am afraid the doctor won't allow it." + +"The doctor?" + +"Yes, have you not heard? Poor father has never been strong for +years back, but this has broken him down completely. He has taken +to his bed, and Dr. Willows says that he is a wreck and that his +nervous system is shattered. Mr. McCarthy was the only man alive +who had known dad in the old days in Victoria." + +"Ha! In Victoria! That is important." + +"Yes, at the mines." + +"Quite so; at the gold-mines, where, as I understand, Mr. Turner +made his money." + +"Yes, certainly." + +"Thank you, Miss Turner. You have been of material assistance to +me." + +"You will tell me if you have any news to-morrow. No doubt you +will go to the prison to see James. Oh, if you do, Mr. Holmes, do +tell him that I know him to be innocent." + +"I will, Miss Turner." + +"I must go home now, for dad is very ill, and he misses me so if +I leave him. Good-bye, and God help you in your undertaking." She +hurried from the room as impulsively as she had entered, and we +heard the wheels of her carriage rattle off down the street. + +"I am ashamed of you, Holmes," said Lestrade with dignity after a +few minutes' silence. "Why should you raise up hopes which you +are bound to disappoint? I am not over-tender of heart, but I +call it cruel." + +"I think that I see my way to clearing James McCarthy," said +Holmes. "Have you an order to see him in prison?" + +"Yes, but only for you and me." + +"Then I shall reconsider my resolution about going out. We have +still time to take a train to Hereford and see him to-night?" + +"Ample." + +"Then let us do so. Watson, I fear that you will find it very +slow, but I shall only be away a couple of hours." + +I walked down to the station with them, and then wandered through +the streets of the little town, finally returning to the hotel, +where I lay upon the sofa and tried to interest myself in a +yellow-backed novel. The puny plot of the story was so thin, +however, when compared to the deep mystery through which we were +groping, and I found my attention wander so continually from the +action to the fact, that I at last flung it across the room and +gave myself up entirely to a consideration of the events of the +day. Supposing that this unhappy young man's story were +absolutely true, then what hellish thing, what absolutely +unforeseen and extraordinary calamity could have occurred between +the time when he parted from his father, and the moment when, +drawn back by his screams, he rushed into the glade? It was +something terrible and deadly. What could it be? Might not the +nature of the injuries reveal something to my medical instincts? +I rang the bell and called for the weekly county paper, which +contained a verbatim account of the inquest. In the surgeon's +deposition it was stated that the posterior third of the left +parietal bone and the left half of the occipital bone had been +shattered by a heavy blow from a blunt weapon. I marked the spot +upon my own head. Clearly such a blow must have been struck from +behind. That was to some extent in favour of the accused, as when +seen quarrelling he was face to face with his father. Still, it +did not go for very much, for the older man might have turned his +back before the blow fell. Still, it might be worth while to call +Holmes' attention to it. Then there was the peculiar dying +reference to a rat. What could that mean? It could not be +delirium. A man dying from a sudden blow does not commonly become +delirious. No, it was more likely to be an attempt to explain how +he met his fate. But what could it indicate? I cudgelled my +brains to find some possible explanation. And then the incident +of the grey cloth seen by young McCarthy. If that were true the +murderer must have dropped some part of his dress, presumably his +overcoat, in his flight, and must have had the hardihood to +return and to carry it away at the instant when the son was +kneeling with his back turned not a dozen paces off. What a +tissue of mysteries and improbabilities the whole thing was! I +did not wonder at Lestrade's opinion, and yet I had so much faith +in Sherlock Holmes' insight that I could not lose hope as long +as every fresh fact seemed to strengthen his conviction of young +McCarthy's innocence. + +It was late before Sherlock Holmes returned. He came back alone, +for Lestrade was staying in lodgings in the town. + +"The glass still keeps very high," he remarked as he sat down. +"It is of importance that it should not rain before we are able +to go over the ground. On the other hand, a man should be at his +very best and keenest for such nice work as that, and I did not +wish to do it when fagged by a long journey. I have seen young +McCarthy." + +"And what did you learn from him?" + +"Nothing." + +"Could he throw no light?" + +"None at all. I was inclined to think at one time that he knew +who had done it and was screening him or her, but I am convinced +now that he is as puzzled as everyone else. He is not a very +quick-witted youth, though comely to look at and, I should think, +sound at heart." + +"I cannot admire his taste," I remarked, "if it is indeed a fact +that he was averse to a marriage with so charming a young lady as +this Miss Turner." + +"Ah, thereby hangs a rather painful tale. This fellow is madly, +insanely, in love with her, but some two years ago, when he was +only a lad, and before he really knew her, for she had been away +five years at a boarding-school, what does the idiot do but get +into the clutches of a barmaid in Bristol and marry her at a +registry office? No one knows a word of the matter, but you can +imagine how maddening it must be to him to be upbraided for not +doing what he would give his very eyes to do, but what he knows +to be absolutely impossible. It was sheer frenzy of this sort +which made him throw his hands up into the air when his father, +at their last interview, was goading him on to propose to Miss +Turner. On the other hand, he had no means of supporting himself, +and his father, who was by all accounts a very hard man, would +have thrown him over utterly had he known the truth. It was with +his barmaid wife that he had spent the last three days in +Bristol, and his father did not know where he was. Mark that +point. It is of importance. Good has come out of evil, however, +for the barmaid, finding from the papers that he is in serious +trouble and likely to be hanged, has thrown him over utterly and +has written to him to say that she has a husband already in the +Bermuda Dockyard, so that there is really no tie between them. I +think that that bit of news has consoled young McCarthy for all +that he has suffered." + +"But if he is innocent, who has done it?" + +"Ah! who? I would call your attention very particularly to two +points. One is that the murdered man had an appointment with +someone at the pool, and that the someone could not have been his +son, for his son was away, and he did not know when he would +return. The second is that the murdered man was heard to cry +'Cooee!' before he knew that his son had returned. Those are the +crucial points upon which the case depends. And now let us talk +about George Meredith, if you please, and we shall leave all +minor matters until to-morrow." + +There was no rain, as Holmes had foretold, and the morning broke +bright and cloudless. At nine o'clock Lestrade called for us with +the carriage, and we set off for Hatherley Farm and the Boscombe +Pool. + +"There is serious news this morning," Lestrade observed. "It is +said that Mr. Turner, of the Hall, is so ill that his life is +despaired of." + +"An elderly man, I presume?" said Holmes. + +"About sixty; but his constitution has been shattered by his life +abroad, and he has been in failing health for some time. This +business has had a very bad effect upon him. He was an old friend +of McCarthy's, and, I may add, a great benefactor to him, for I +have learned that he gave him Hatherley Farm rent free." + +"Indeed! That is interesting," said Holmes. + +"Oh, yes! In a hundred other ways he has helped him. Everybody +about here speaks of his kindness to him." + +"Really! Does it not strike you as a little singular that this +McCarthy, who appears to have had little of his own, and to have +been under such obligations to Turner, should still talk of +marrying his son to Turner's daughter, who is, presumably, +heiress to the estate, and that in such a very cocksure manner, +as if it were merely a case of a proposal and all else would +follow? It is the more strange, since we know that Turner himself +was averse to the idea. The daughter told us as much. Do you not +deduce something from that?" + +"We have got to the deductions and the inferences," said +Lestrade, winking at me. "I find it hard enough to tackle facts, +Holmes, without flying away after theories and fancies." + +"You are right," said Holmes demurely; "you do find it very hard +to tackle the facts." + +"Anyhow, I have grasped one fact which you seem to find it +difficult to get hold of," replied Lestrade with some warmth. + +"And that is--" + +"That McCarthy senior met his death from McCarthy junior and that +all theories to the contrary are the merest moonshine." + +"Well, moonshine is a brighter thing than fog," said Holmes, +laughing. "But I am very much mistaken if this is not Hatherley +Farm upon the left." + +"Yes, that is it." It was a widespread, comfortable-looking +building, two-storied, slate-roofed, with great yellow blotches +of lichen upon the grey walls. The drawn blinds and the smokeless +chimneys, however, gave it a stricken look, as though the weight +of this horror still lay heavy upon it. We called at the door, +when the maid, at Holmes' request, showed us the boots which her +master wore at the time of his death, and also a pair of the +son's, though not the pair which he had then had. Having measured +these very carefully from seven or eight different points, Holmes +desired to be led to the court-yard, from which we all followed +the winding track which led to Boscombe Pool. + +Sherlock Holmes was transformed when he was hot upon such a scent +as this. Men who had only known the quiet thinker and logician of +Baker Street would have failed to recognise him. His face flushed +and darkened. His brows were drawn into two hard black lines, +while his eyes shone out from beneath them with a steely glitter. +His face was bent downward, his shoulders bowed, his lips +compressed, and the veins stood out like whipcord in his long, +sinewy neck. His nostrils seemed to dilate with a purely animal +lust for the chase, and his mind was so absolutely concentrated +upon the matter before him that a question or remark fell +unheeded upon his ears, or, at the most, only provoked a quick, +impatient snarl in reply. Swiftly and silently he made his way +along the track which ran through the meadows, and so by way of +the woods to the Boscombe Pool. It was damp, marshy ground, as is +all that district, and there were marks of many feet, both upon +the path and amid the short grass which bounded it on either +side. Sometimes Holmes would hurry on, sometimes stop dead, and +once he made quite a little detour into the meadow. Lestrade and +I walked behind him, the detective indifferent and contemptuous, +while I watched my friend with the interest which sprang from the +conviction that every one of his actions was directed towards a +definite end. + +The Boscombe Pool, which is a little reed-girt sheet of water +some fifty yards across, is situated at the boundary between the +Hatherley Farm and the private park of the wealthy Mr. Turner. +Above the woods which lined it upon the farther side we could see +the red, jutting pinnacles which marked the site of the rich +landowner's dwelling. On the Hatherley side of the pool the woods +grew very thick, and there was a narrow belt of sodden grass +twenty paces across between the edge of the trees and the reeds +which lined the lake. Lestrade showed us the exact spot at which +the body had been found, and, indeed, so moist was the ground, +that I could plainly see the traces which had been left by the +fall of the stricken man. To Holmes, as I could see by his eager +face and peering eyes, very many other things were to be read +upon the trampled grass. He ran round, like a dog who is picking +up a scent, and then turned upon my companion. + +"What did you go into the pool for?" he asked. + +"I fished about with a rake. I thought there might be some weapon +or other trace. But how on earth--" + +"Oh, tut, tut! I have no time! That left foot of yours with its +inward twist is all over the place. A mole could trace it, and +there it vanishes among the reeds. Oh, how simple it would all +have been had I been here before they came like a herd of buffalo +and wallowed all over it. Here is where the party with the +lodge-keeper came, and they have covered all tracks for six or +eight feet round the body. But here are three separate tracks of +the same feet." He drew out a lens and lay down upon his +waterproof to have a better view, talking all the time rather to +himself than to us. "These are young McCarthy's feet. Twice he +was walking, and once he ran swiftly, so that the soles are +deeply marked and the heels hardly visible. That bears out his +story. He ran when he saw his father on the ground. Then here are +the father's feet as he paced up and down. What is this, then? It +is the butt-end of the gun as the son stood listening. And this? +Ha, ha! What have we here? Tiptoes! tiptoes! Square, too, quite +unusual boots! They come, they go, they come again--of course +that was for the cloak. Now where did they come from?" He ran up +and down, sometimes losing, sometimes finding the track until we +were well within the edge of the wood and under the shadow of a +great beech, the largest tree in the neighbourhood. Holmes traced +his way to the farther side of this and lay down once more upon +his face with a little cry of satisfaction. For a long time he +remained there, turning over the leaves and dried sticks, +gathering up what seemed to me to be dust into an envelope and +examining with his lens not only the ground but even the bark of +the tree as far as he could reach. A jagged stone was lying among +the moss, and this also he carefully examined and retained. Then +he followed a pathway through the wood until he came to the +highroad, where all traces were lost. + +"It has been a case of considerable interest," he remarked, +returning to his natural manner. "I fancy that this grey house on +the right must be the lodge. I think that I will go in and have a +word with Moran, and perhaps write a little note. Having done +that, we may drive back to our luncheon. You may walk to the cab, +and I shall be with you presently." + +It was about ten minutes before we regained our cab and drove +back into Ross, Holmes still carrying with him the stone which he +had picked up in the wood. + +"This may interest you, Lestrade," he remarked, holding it out. +"The murder was done with it." + +"I see no marks." + +"There are none." + +"How do you know, then?" + +"The grass was growing under it. It had only lain there a few +days. There was no sign of a place whence it had been taken. It +corresponds with the injuries. There is no sign of any other +weapon." + +"And the murderer?" + +"Is a tall man, left-handed, limps with the right leg, wears +thick-soled shooting-boots and a grey cloak, smokes Indian +cigars, uses a cigar-holder, and carries a blunt pen-knife in his +pocket. There are several other indications, but these may be +enough to aid us in our search." + +Lestrade laughed. "I am afraid that I am still a sceptic," he +said. "Theories are all very well, but we have to deal with a +hard-headed British jury." + +"Nous verrons," answered Holmes calmly. "You work your own +method, and I shall work mine. I shall be busy this afternoon, +and shall probably return to London by the evening train." + +"And leave your case unfinished?" + +"No, finished." + +"But the mystery?" + +"It is solved." + +"Who was the criminal, then?" + +"The gentleman I describe." + +"But who is he?" + +"Surely it would not be difficult to find out. This is not such a +populous neighbourhood." + +Lestrade shrugged his shoulders. "I am a practical man," he said, +"and I really cannot undertake to go about the country looking +for a left-handed gentleman with a game leg. I should become the +laughing-stock of Scotland Yard." + +"All right," said Holmes quietly. "I have given you the chance. +Here are your lodgings. Good-bye. I shall drop you a line before +I leave." + +Having left Lestrade at his rooms, we drove to our hotel, where +we found lunch upon the table. Holmes was silent and buried in +thought with a pained expression upon his face, as one who finds +himself in a perplexing position. + +"Look here, Watson," he said when the cloth was cleared "just sit +down in this chair and let me preach to you for a little. I don't +know quite what to do, and I should value your advice. Light a +cigar and let me expound." + + "Pray do so." + +"Well, now, in considering this case there are two points about +young McCarthy's narrative which struck us both instantly, +although they impressed me in his favour and you against him. One +was the fact that his father should, according to his account, +cry 'Cooee!' before seeing him. The other was his singular dying +reference to a rat. He mumbled several words, you understand, but +that was all that caught the son's ear. Now from this double +point our research must commence, and we will begin it by +presuming that what the lad says is absolutely true." + +"What of this 'Cooee!' then?" + +"Well, obviously it could not have been meant for the son. The +son, as far as he knew, was in Bristol. It was mere chance that +he was within earshot. The 'Cooee!' was meant to attract the +attention of whoever it was that he had the appointment with. But +'Cooee' is a distinctly Australian cry, and one which is used +between Australians. There is a strong presumption that the +person whom McCarthy expected to meet him at Boscombe Pool was +someone who had been in Australia." + +"What of the rat, then?" + +Sherlock Holmes took a folded paper from his pocket and flattened +it out on the table. "This is a map of the Colony of Victoria," +he said. "I wired to Bristol for it last night." He put his hand +over part of the map. "What do you read?" + +"ARAT," I read. + +"And now?" He raised his hand. + +"BALLARAT." + +"Quite so. That was the word the man uttered, and of which his +son only caught the last two syllables. He was trying to utter +the name of his murderer. So and so, of Ballarat." + +"It is wonderful!" I exclaimed. + +"It is obvious. And now, you see, I had narrowed the field down +considerably. The possession of a grey garment was a third point +which, granting the son's statement to be correct, was a +certainty. We have come now out of mere vagueness to the definite +conception of an Australian from Ballarat with a grey cloak." + +"Certainly." + +"And one who was at home in the district, for the pool can only +be approached by the farm or by the estate, where strangers could +hardly wander." + +"Quite so." + +"Then comes our expedition of to-day. By an examination of the +ground I gained the trifling details which I gave to that +imbecile Lestrade, as to the personality of the criminal." + +"But how did you gain them?" + +"You know my method. It is founded upon the observation of +trifles." + +"His height I know that you might roughly judge from the length +of his stride. His boots, too, might be told from their traces." + +"Yes, they were peculiar boots." + +"But his lameness?" + +"The impression of his right foot was always less distinct than +his left. He put less weight upon it. Why? Because he limped--he +was lame." + +"But his left-handedness." + +"You were yourself struck by the nature of the injury as recorded +by the surgeon at the inquest. The blow was struck from +immediately behind, and yet was upon the left side. Now, how can +that be unless it were by a left-handed man? He had stood behind +that tree during the interview between the father and son. He had +even smoked there. I found the ash of a cigar, which my special +knowledge of tobacco ashes enables me to pronounce as an Indian +cigar. I have, as you know, devoted some attention to this, and +written a little monograph on the ashes of 140 different +varieties of pipe, cigar, and cigarette tobacco. Having found the +ash, I then looked round and discovered the stump among the moss +where he had tossed it. It was an Indian cigar, of the variety +which are rolled in Rotterdam." + +"And the cigar-holder?" + +"I could see that the end had not been in his mouth. Therefore he +used a holder. The tip had been cut off, not bitten off, but the +cut was not a clean one, so I deduced a blunt pen-knife." + +"Holmes," I said, "you have drawn a net round this man from which +he cannot escape, and you have saved an innocent human life as +truly as if you had cut the cord which was hanging him. I see the +direction in which all this points. The culprit is--" + +"Mr. John Turner," cried the hotel waiter, opening the door of +our sitting-room, and ushering in a visitor. + +The man who entered was a strange and impressive figure. His +slow, limping step and bowed shoulders gave the appearance of +decrepitude, and yet his hard, deep-lined, craggy features, and +his enormous limbs showed that he was possessed of unusual +strength of body and of character. His tangled beard, grizzled +hair, and outstanding, drooping eyebrows combined to give an air +of dignity and power to his appearance, but his face was of an +ashen white, while his lips and the corners of his nostrils were +tinged with a shade of blue. It was clear to me at a glance that +he was in the grip of some deadly and chronic disease. + +"Pray sit down on the sofa," said Holmes gently. "You had my +note?" + +"Yes, the lodge-keeper brought it up. You said that you wished to +see me here to avoid scandal." + +"I thought people would talk if I went to the Hall." + +"And why did you wish to see me?" He looked across at my +companion with despair in his weary eyes, as though his question +was already answered. + +"Yes," said Holmes, answering the look rather than the words. "It +is so. I know all about McCarthy." + +The old man sank his face in his hands. "God help me!" he cried. +"But I would not have let the young man come to harm. I give you +my word that I would have spoken out if it went against him at +the Assizes." + +"I am glad to hear you say so," said Holmes gravely. + +"I would have spoken now had it not been for my dear girl. It +would break her heart--it will break her heart when she hears +that I am arrested." + +"It may not come to that," said Holmes. + +"What?" + +"I am no official agent. I understand that it was your daughter +who required my presence here, and I am acting in her interests. +Young McCarthy must be got off, however." + +"I am a dying man," said old Turner. "I have had diabetes for +years. My doctor says it is a question whether I shall live a +month. Yet I would rather die under my own roof than in a gaol." + +Holmes rose and sat down at the table with his pen in his hand +and a bundle of paper before him. "Just tell us the truth," he +said. "I shall jot down the facts. You will sign it, and Watson +here can witness it. Then I could produce your confession at the +last extremity to save young McCarthy. I promise you that I shall +not use it unless it is absolutely needed." + +"It's as well," said the old man; "it's a question whether I +shall live to the Assizes, so it matters little to me, but I +should wish to spare Alice the shock. And now I will make the +thing clear to you; it has been a long time in the acting, but +will not take me long to tell. + +"You didn't know this dead man, McCarthy. He was a devil +incarnate. I tell you that. God keep you out of the clutches of +such a man as he. His grip has been upon me these twenty years, +and he has blasted my life. I'll tell you first how I came to be +in his power. + +"It was in the early '60's at the diggings. I was a young chap +then, hot-blooded and reckless, ready to turn my hand at +anything; I got among bad companions, took to drink, had no luck +with my claim, took to the bush, and in a word became what you +would call over here a highway robber. There were six of us, and +we had a wild, free life of it, sticking up a station from time +to time, or stopping the wagons on the road to the diggings. +Black Jack of Ballarat was the name I went under, and our party +is still remembered in the colony as the Ballarat Gang. + +"One day a gold convoy came down from Ballarat to Melbourne, and +we lay in wait for it and attacked it. There were six troopers +and six of us, so it was a close thing, but we emptied four of +their saddles at the first volley. Three of our boys were killed, +however, before we got the swag. I put my pistol to the head of +the wagon-driver, who was this very man McCarthy. I wish to the +Lord that I had shot him then, but I spared him, though I saw his +wicked little eyes fixed on my face, as though to remember every +feature. We got away with the gold, became wealthy men, and made +our way over to England without being suspected. There I parted +from my old pals and determined to settle down to a quiet and +respectable life. I bought this estate, which chanced to be in +the market, and I set myself to do a little good with my money, +to make up for the way in which I had earned it. I married, too, +and though my wife died young she left me my dear little Alice. +Even when she was just a baby her wee hand seemed to lead me down +the right path as nothing else had ever done. In a word, I turned +over a new leaf and did my best to make up for the past. All was +going well when McCarthy laid his grip upon me. + +"I had gone up to town about an investment, and I met him in +Regent Street with hardly a coat to his back or a boot to his +foot. + +"'Here we are, Jack,' says he, touching me on the arm; 'we'll be +as good as a family to you. There's two of us, me and my son, and +you can have the keeping of us. If you don't--it's a fine, +law-abiding country is England, and there's always a policeman +within hail.' + +"Well, down they came to the west country, there was no shaking +them off, and there they have lived rent free on my best land +ever since. There was no rest for me, no peace, no forgetfulness; +turn where I would, there was his cunning, grinning face at my +elbow. It grew worse as Alice grew up, for he soon saw I was more +afraid of her knowing my past than of the police. Whatever he +wanted he must have, and whatever it was I gave him without +question, land, money, houses, until at last he asked a thing +which I could not give. He asked for Alice. + +"His son, you see, had grown up, and so had my girl, and as I was +known to be in weak health, it seemed a fine stroke to him that +his lad should step into the whole property. But there I was +firm. I would not have his cursed stock mixed with mine; not that +I had any dislike to the lad, but his blood was in him, and that +was enough. I stood firm. McCarthy threatened. I braved him to do +his worst. We were to meet at the pool midway between our houses +to talk it over. + +"When I went down there I found him talking with his son, so I +smoked a cigar and waited behind a tree until he should be alone. +But as I listened to his talk all that was black and bitter in +me seemed to come uppermost. He was urging his son to marry my +daughter with as little regard for what she might think as if she +were a slut from off the streets. It drove me mad to think that I +and all that I held most dear should be in the power of such a +man as this. Could I not snap the bond? I was already a dying and +a desperate man. Though clear of mind and fairly strong of limb, +I knew that my own fate was sealed. But my memory and my girl! +Both could be saved if I could but silence that foul tongue. I +did it, Mr. Holmes. I would do it again. Deeply as I have sinned, +I have led a life of martyrdom to atone for it. But that my girl +should be entangled in the same meshes which held me was more +than I could suffer. I struck him down with no more compunction +than if he had been some foul and venomous beast. His cry brought +back his son; but I had gained the cover of the wood, though I +was forced to go back to fetch the cloak which I had dropped in +my flight. That is the true story, gentlemen, of all that +occurred." + +"Well, it is not for me to judge you," said Holmes as the old man +signed the statement which had been drawn out. "I pray that we +may never be exposed to such a temptation." + +"I pray not, sir. And what do you intend to do?" + +"In view of your health, nothing. You are yourself aware that you +will soon have to answer for your deed at a higher court than the +Assizes. I will keep your confession, and if McCarthy is +condemned I shall be forced to use it. If not, it shall never be +seen by mortal eye; and your secret, whether you be alive or +dead, shall be safe with us." + +"Farewell, then," said the old man solemnly. "Your own deathbeds, +when they come, will be the easier for the thought of the peace +which you have given to mine." Tottering and shaking in all his +giant frame, he stumbled slowly from the room. + +"God help us!" said Holmes after a long silence. "Why does fate +play such tricks with poor, helpless worms? I never hear of such +a case as this that I do not think of Baxter's words, and say, +'There, but for the grace of God, goes Sherlock Holmes.'" + +James McCarthy was acquitted at the Assizes on the strength of a +number of objections which had been drawn out by Holmes and +submitted to the defending counsel. Old Turner lived for seven +months after our interview, but he is now dead; and there is +every prospect that the son and daughter may come to live happily +together in ignorance of the black cloud which rests upon their +past. + + + +ADVENTURE V. THE FIVE ORANGE PIPS + +When I glance over my notes and records of the Sherlock Holmes +cases between the years '82 and '90, I am faced by so many which +present strange and interesting features that it is no easy +matter to know which to choose and which to leave. Some, however, +have already gained publicity through the papers, and others have +not offered a field for those peculiar qualities which my friend +possessed in so high a degree, and which it is the object of +these papers to illustrate. Some, too, have baffled his +analytical skill, and would be, as narratives, beginnings without +an ending, while others have been but partially cleared up, and +have their explanations founded rather upon conjecture and +surmise than on that absolute logical proof which was so dear to +him. There is, however, one of these last which was so remarkable +in its details and so startling in its results that I am tempted +to give some account of it in spite of the fact that there are +points in connection with it which never have been, and probably +never will be, entirely cleared up. + +The year '87 furnished us with a long series of cases of greater +or less interest, of which I retain the records. Among my +headings under this one twelve months I find an account of the +adventure of the Paradol Chamber, of the Amateur Mendicant +Society, who held a luxurious club in the lower vault of a +furniture warehouse, of the facts connected with the loss of the +British barque "Sophy Anderson", of the singular adventures of the +Grice Patersons in the island of Uffa, and finally of the +Camberwell poisoning case. In the latter, as may be remembered, +Sherlock Holmes was able, by winding up the dead man's watch, to +prove that it had been wound up two hours before, and that +therefore the deceased had gone to bed within that time--a +deduction which was of the greatest importance in clearing up the +case. All these I may sketch out at some future date, but none of +them present such singular features as the strange train of +circumstances which I have now taken up my pen to describe. + +It was in the latter days of September, and the equinoctial gales +had set in with exceptional violence. All day the wind had +screamed and the rain had beaten against the windows, so that +even here in the heart of great, hand-made London we were forced +to raise our minds for the instant from the routine of life and +to recognise the presence of those great elemental forces which +shriek at mankind through the bars of his civilisation, like +untamed beasts in a cage. As evening drew in, the storm grew +higher and louder, and the wind cried and sobbed like a child in +the chimney. Sherlock Holmes sat moodily at one side of the +fireplace cross-indexing his records of crime, while I at the +other was deep in one of Clark Russell's fine sea-stories until +the howl of the gale from without seemed to blend with the text, +and the splash of the rain to lengthen out into the long swash of +the sea waves. My wife was on a visit to her mother's, and for a +few days I was a dweller once more in my old quarters at Baker +Street. + +"Why," said I, glancing up at my companion, "that was surely the +bell. Who could come to-night? Some friend of yours, perhaps?" + +"Except yourself I have none," he answered. "I do not encourage +visitors." + +"A client, then?" + +"If so, it is a serious case. Nothing less would bring a man out +on such a day and at such an hour. But I take it that it is more +likely to be some crony of the landlady's." + +Sherlock Holmes was wrong in his conjecture, however, for there +came a step in the passage and a tapping at the door. He +stretched out his long arm to turn the lamp away from himself and +towards the vacant chair upon which a newcomer must sit. + +"Come in!" said he. + +The man who entered was young, some two-and-twenty at the +outside, well-groomed and trimly clad, with something of +refinement and delicacy in his bearing. The streaming umbrella +which he held in his hand, and his long shining waterproof told +of the fierce weather through which he had come. He looked about +him anxiously in the glare of the lamp, and I could see that his +face was pale and his eyes heavy, like those of a man who is +weighed down with some great anxiety. + +"I owe you an apology," he said, raising his golden pince-nez to +his eyes. "I trust that I am not intruding. I fear that I have +brought some traces of the storm and rain into your snug +chamber." + +"Give me your coat and umbrella," said Holmes. "They may rest +here on the hook and will be dry presently. You have come up from +the south-west, I see." + +"Yes, from Horsham." + +"That clay and chalk mixture which I see upon your toe caps is +quite distinctive." + +"I have come for advice." + +"That is easily got." + +"And help." + +"That is not always so easy." + +"I have heard of you, Mr. Holmes. I heard from Major Prendergast +how you saved him in the Tankerville Club scandal." + +"Ah, of course. He was wrongfully accused of cheating at cards." + +"He said that you could solve anything." + +"He said too much." + +"That you are never beaten." + +"I have been beaten four times--three times by men, and once by a +woman." + +"But what is that compared with the number of your successes?" + +"It is true that I have been generally successful." + +"Then you may be so with me." + +"I beg that you will draw your chair up to the fire and favour me +with some details as to your case." + +"It is no ordinary one." + +"None of those which come to me are. I am the last court of +appeal." + +"And yet I question, sir, whether, in all your experience, you +have ever listened to a more mysterious and inexplicable chain of +events than those which have happened in my own family." + +"You fill me with interest," said Holmes. "Pray give us the +essential facts from the commencement, and I can afterwards +question you as to those details which seem to me to be most +important." + +The young man pulled his chair up and pushed his wet feet out +towards the blaze. + +"My name," said he, "is John Openshaw, but my own affairs have, +as far as I can understand, little to do with this awful +business. It is a hereditary matter; so in order to give you an +idea of the facts, I must go back to the commencement of the +affair. + +"You must know that my grandfather had two sons--my uncle Elias +and my father Joseph. My father had a small factory at Coventry, +which he enlarged at the time of the invention of bicycling. He +was a patentee of the Openshaw unbreakable tire, and his business +met with such success that he was able to sell it and to retire +upon a handsome competence. + +"My uncle Elias emigrated to America when he was a young man and +became a planter in Florida, where he was reported to have done +very well. At the time of the war he fought in Jackson's army, +and afterwards under Hood, where he rose to be a colonel. When +Lee laid down his arms my uncle returned to his plantation, where +he remained for three or four years. About 1869 or 1870 he came +back to Europe and took a small estate in Sussex, near Horsham. +He had made a very considerable fortune in the States, and his +reason for leaving them was his aversion to the negroes, and his +dislike of the Republican policy in extending the franchise to +them. He was a singular man, fierce and quick-tempered, very +foul-mouthed when he was angry, and of a most retiring +disposition. During all the years that he lived at Horsham, I +doubt if ever he set foot in the town. He had a garden and two or +three fields round his house, and there he would take his +exercise, though very often for weeks on end he would never leave +his room. He drank a great deal of brandy and smoked very +heavily, but he would see no society and did not want any +friends, not even his own brother. + +"He didn't mind me; in fact, he took a fancy to me, for at the +time when he saw me first I was a youngster of twelve or so. This +would be in the year 1878, after he had been eight or nine years +in England. He begged my father to let me live with him and he +was very kind to me in his way. When he was sober he used to be +fond of playing backgammon and draughts with me, and he would +make me his representative both with the servants and with the +tradespeople, so that by the time that I was sixteen I was quite +master of the house. I kept all the keys and could go where I +liked and do what I liked, so long as I did not disturb him in +his privacy. There was one singular exception, however, for he +had a single room, a lumber-room up among the attics, which was +invariably locked, and which he would never permit either me or +anyone else to enter. With a boy's curiosity I have peeped +through the keyhole, but I was never able to see more than such a +collection of old trunks and bundles as would be expected in such +a room. + +"One day--it was in March, 1883--a letter with a foreign stamp +lay upon the table in front of the colonel's plate. It was not a +common thing for him to receive letters, for his bills were all +paid in ready money, and he had no friends of any sort. 'From +India!' said he as he took it up, 'Pondicherry postmark! What can +this be?' Opening it hurriedly, out there jumped five little +dried orange pips, which pattered down upon his plate. I began to +laugh at this, but the laugh was struck from my lips at the sight +of his face. His lip had fallen, his eyes were protruding, his +skin the colour of putty, and he glared at the envelope which he +still held in his trembling hand, 'K. K. K.!' he shrieked, and +then, 'My God, my God, my sins have overtaken me!' + +"'What is it, uncle?' I cried. + +"'Death,' said he, and rising from the table he retired to his +room, leaving me palpitating with horror. I took up the envelope +and saw scrawled in red ink upon the inner flap, just above the +gum, the letter K three times repeated. There was nothing else +save the five dried pips. What could be the reason of his +overpowering terror? I left the breakfast-table, and as I +ascended the stair I met him coming down with an old rusty key, +which must have belonged to the attic, in one hand, and a small +brass box, like a cashbox, in the other. + +"'They may do what they like, but I'll checkmate them still,' +said he with an oath. 'Tell Mary that I shall want a fire in my +room to-day, and send down to Fordham, the Horsham lawyer.' + +"I did as he ordered, and when the lawyer arrived I was asked to +step up to the room. The fire was burning brightly, and in the +grate there was a mass of black, fluffy ashes, as of burned +paper, while the brass box stood open and empty beside it. As I +glanced at the box I noticed, with a start, that upon the lid was +printed the treble K which I had read in the morning upon the +envelope. + +"'I wish you, John,' said my uncle, 'to witness my will. I leave +my estate, with all its advantages and all its disadvantages, to +my brother, your father, whence it will, no doubt, descend to +you. If you can enjoy it in peace, well and good! If you find you +cannot, take my advice, my boy, and leave it to your deadliest +enemy. I am sorry to give you such a two-edged thing, but I can't +say what turn things are going to take. Kindly sign the paper +where Mr. Fordham shows you.' + +"I signed the paper as directed, and the lawyer took it away with +him. The singular incident made, as you may think, the deepest +impression upon me, and I pondered over it and turned it every +way in my mind without being able to make anything of it. Yet I +could not shake off the vague feeling of dread which it left +behind, though the sensation grew less keen as the weeks passed +and nothing happened to disturb the usual routine of our lives. I +could see a change in my uncle, however. He drank more than ever, +and he was less inclined for any sort of society. Most of his +time he would spend in his room, with the door locked upon the +inside, but sometimes he would emerge in a sort of drunken frenzy +and would burst out of the house and tear about the garden with a +revolver in his hand, screaming out that he was afraid of no man, +and that he was not to be cooped up, like a sheep in a pen, by +man or devil. When these hot fits were over, however, he would +rush tumultuously in at the door and lock and bar it behind him, +like a man who can brazen it out no longer against the terror +which lies at the roots of his soul. At such times I have seen +his face, even on a cold day, glisten with moisture, as though it +were new raised from a basin. + +"Well, to come to an end of the matter, Mr. Holmes, and not to +abuse your patience, there came a night when he made one of those +drunken sallies from which he never came back. We found him, when +we went to search for him, face downward in a little +green-scummed pool, which lay at the foot of the garden. There +was no sign of any violence, and the water was but two feet deep, +so that the jury, having regard to his known eccentricity, +brought in a verdict of 'suicide.' But I, who knew how he winced +from the very thought of death, had much ado to persuade myself +that he had gone out of his way to meet it. The matter passed, +however, and my father entered into possession of the estate, and +of some 14,000 pounds, which lay to his credit at the bank." + +"One moment," Holmes interposed, "your statement is, I foresee, +one of the most remarkable to which I have ever listened. Let me +have the date of the reception by your uncle of the letter, and +the date of his supposed suicide." + +"The letter arrived on March 10, 1883. His death was seven weeks +later, upon the night of May 2nd." + +"Thank you. Pray proceed." + +"When my father took over the Horsham property, he, at my +request, made a careful examination of the attic, which had been +always locked up. We found the brass box there, although its +contents had been destroyed. On the inside of the cover was a +paper label, with the initials of K. K. K. repeated upon it, and +'Letters, memoranda, receipts, and a register' written beneath. +These, we presume, indicated the nature of the papers which had +been destroyed by Colonel Openshaw. For the rest, there was +nothing of much importance in the attic save a great many +scattered papers and note-books bearing upon my uncle's life in +America. Some of them were of the war time and showed that he had +done his duty well and had borne the repute of a brave soldier. +Others were of a date during the reconstruction of the Southern +states, and were mostly concerned with politics, for he had +evidently taken a strong part in opposing the carpet-bag +politicians who had been sent down from the North. + +"Well, it was the beginning of '84 when my father came to live at +Horsham, and all went as well as possible with us until the +January of '85. On the fourth day after the new year I heard my +father give a sharp cry of surprise as we sat together at the +breakfast-table. There he was, sitting with a newly opened +envelope in one hand and five dried orange pips in the +outstretched palm of the other one. He had always laughed at what +he called my cock-and-bull story about the colonel, but he looked +very scared and puzzled now that the same thing had come upon +himself. + +"'Why, what on earth does this mean, John?' he stammered. + +"My heart had turned to lead. 'It is K. K. K.,' said I. + +"He looked inside the envelope. 'So it is,' he cried. 'Here are +the very letters. But what is this written above them?' + +"'Put the papers on the sundial,' I read, peeping over his +shoulder. + +"'What papers? What sundial?' he asked. + +"'The sundial in the garden. There is no other,' said I; 'but the +papers must be those that are destroyed.' + +"'Pooh!' said he, gripping hard at his courage. 'We are in a +civilised land here, and we can't have tomfoolery of this kind. +Where does the thing come from?' + +"'From Dundee,' I answered, glancing at the postmark. + +"'Some preposterous practical joke,' said he. 'What have I to do +with sundials and papers? I shall take no notice of such +nonsense.' + +"'I should certainly speak to the police,' I said. + +"'And be laughed at for my pains. Nothing of the sort.' + +"'Then let me do so?' + +"'No, I forbid you. I won't have a fuss made about such +nonsense.' + +"It was in vain to argue with him, for he was a very obstinate +man. I went about, however, with a heart which was full of +forebodings. + +"On the third day after the coming of the letter my father went +from home to visit an old friend of his, Major Freebody, who is +in command of one of the forts upon Portsdown Hill. I was glad +that he should go, for it seemed to me that he was farther from +danger when he was away from home. In that, however, I was in +error. Upon the second day of his absence I received a telegram +from the major, imploring me to come at once. My father had +fallen over one of the deep chalk-pits which abound in the +neighbourhood, and was lying senseless, with a shattered skull. I +hurried to him, but he passed away without having ever recovered +his consciousness. He had, as it appears, been returning from +Fareham in the twilight, and as the country was unknown to him, +and the chalk-pit unfenced, the jury had no hesitation in +bringing in a verdict of 'death from accidental causes.' +Carefully as I examined every fact connected with his death, I +was unable to find anything which could suggest the idea of +murder. There were no signs of violence, no footmarks, no +robbery, no record of strangers having been seen upon the roads. +And yet I need not tell you that my mind was far from at ease, +and that I was well-nigh certain that some foul plot had been +woven round him. + +"In this sinister way I came into my inheritance. You will ask me +why I did not dispose of it? I answer, because I was well +convinced that our troubles were in some way dependent upon an +incident in my uncle's life, and that the danger would be as +pressing in one house as in another. + +"It was in January, '85, that my poor father met his end, and two +years and eight months have elapsed since then. During that time +I have lived happily at Horsham, and I had begun to hope that +this curse had passed away from the family, and that it had ended +with the last generation. I had begun to take comfort too soon, +however; yesterday morning the blow fell in the very shape in +which it had come upon my father." + +The young man took from his waistcoat a crumpled envelope, and +turning to the table he shook out upon it five little dried +orange pips. + +"This is the envelope," he continued. "The postmark is +London--eastern division. Within are the very words which were +upon my father's last message: 'K. K. K.'; and then 'Put the +papers on the sundial.'" + +"What have you done?" asked Holmes. + +"Nothing." + +"Nothing?" + +"To tell the truth"--he sank his face into his thin, white +hands--"I have felt helpless. I have felt like one of those poor +rabbits when the snake is writhing towards it. I seem to be in +the grasp of some resistless, inexorable evil, which no foresight +and no precautions can guard against." + +"Tut! tut!" cried Sherlock Holmes. "You must act, man, or you are +lost. Nothing but energy can save you. This is no time for +despair." + +"I have seen the police." + +"Ah!" + +"But they listened to my story with a smile. I am convinced that +the inspector has formed the opinion that the letters are all +practical jokes, and that the deaths of my relations were really +accidents, as the jury stated, and were not to be connected with +the warnings." + +Holmes shook his clenched hands in the air. "Incredible +imbecility!" he cried. + +"They have, however, allowed me a policeman, who may remain in +the house with me." + +"Has he come with you to-night?" + +"No. His orders were to stay in the house." + +Again Holmes raved in the air. + +"Why did you come to me," he cried, "and, above all, why did you +not come at once?" + +"I did not know. It was only to-day that I spoke to Major +Prendergast about my troubles and was advised by him to come to +you." + +"It is really two days since you had the letter. We should have +acted before this. You have no further evidence, I suppose, than +that which you have placed before us--no suggestive detail which +might help us?" + +"There is one thing," said John Openshaw. He rummaged in his coat +pocket, and, drawing out a piece of discoloured, blue-tinted +paper, he laid it out upon the table. "I have some remembrance," +said he, "that on the day when my uncle burned the papers I +observed that the small, unburned margins which lay amid the +ashes were of this particular colour. I found this single sheet +upon the floor of his room, and I am inclined to think that it +may be one of the papers which has, perhaps, fluttered out from +among the others, and in that way has escaped destruction. Beyond +the mention of pips, I do not see that it helps us much. I think +myself that it is a page from some private diary. The writing is +undoubtedly my uncle's." + +Holmes moved the lamp, and we both bent over the sheet of paper, +which showed by its ragged edge that it had indeed been torn from +a book. It was headed, "March, 1869," and beneath were the +following enigmatical notices: + +"4th. Hudson came. Same old platform. + +"7th. Set the pips on McCauley, Paramore, and + John Swain, of St. Augustine. + +"9th. McCauley cleared. + +"10th. John Swain cleared. + +"12th. Visited Paramore. All well." + +"Thank you!" said Holmes, folding up the paper and returning it +to our visitor. "And now you must on no account lose another +instant. We cannot spare time even to discuss what you have told +me. You must get home instantly and act." + +"What shall I do?" + +"There is but one thing to do. It must be done at once. You must +put this piece of paper which you have shown us into the brass +box which you have described. You must also put in a note to say +that all the other papers were burned by your uncle, and that +this is the only one which remains. You must assert that in such +words as will carry conviction with them. Having done this, you +must at once put the box out upon the sundial, as directed. Do +you understand?" + +"Entirely." + +"Do not think of revenge, or anything of the sort, at present. I +think that we may gain that by means of the law; but we have our +web to weave, while theirs is already woven. The first +consideration is to remove the pressing danger which threatens +you. The second is to clear up the mystery and to punish the +guilty parties." + +"I thank you," said the young man, rising and pulling on his +overcoat. "You have given me fresh life and hope. I shall +certainly do as you advise." + +"Do not lose an instant. And, above all, take care of yourself in +the meanwhile, for I do not think that there can be a doubt that +you are threatened by a very real and imminent danger. How do you +go back?" + +"By train from Waterloo." + +"It is not yet nine. The streets will be crowded, so I trust that +you may be in safety. And yet you cannot guard yourself too +closely." + +"I am armed." + +"That is well. To-morrow I shall set to work upon your case." + +"I shall see you at Horsham, then?" + +"No, your secret lies in London. It is there that I shall seek +it." + +"Then I shall call upon you in a day, or in two days, with news +as to the box and the papers. I shall take your advice in every +particular." He shook hands with us and took his leave. Outside +the wind still screamed and the rain splashed and pattered +against the windows. This strange, wild story seemed to have come +to us from amid the mad elements--blown in upon us like a sheet +of sea-weed in a gale--and now to have been reabsorbed by them +once more. + +Sherlock Holmes sat for some time in silence, with his head sunk +forward and his eyes bent upon the red glow of the fire. Then he +lit his pipe, and leaning back in his chair he watched the blue +smoke-rings as they chased each other up to the ceiling. + +"I think, Watson," he remarked at last, "that of all our cases we +have had none more fantastic than this." + +"Save, perhaps, the Sign of Four." + +"Well, yes. Save, perhaps, that. And yet this John Openshaw seems +to me to be walking amid even greater perils than did the +Sholtos." + +"But have you," I asked, "formed any definite conception as to +what these perils are?" + +"There can be no question as to their nature," he answered. + +"Then what are they? Who is this K. K. K., and why does he pursue +this unhappy family?" + +Sherlock Holmes closed his eyes and placed his elbows upon the +arms of his chair, with his finger-tips together. "The ideal +reasoner," he remarked, "would, when he had once been shown a +single fact in all its bearings, deduce from it not only all the +chain of events which led up to it but also all the results which +would follow from it. As Cuvier could correctly describe a whole +animal by the contemplation of a single bone, so the observer who +has thoroughly understood one link in a series of incidents +should be able to accurately state all the other ones, both +before and after. We have not yet grasped the results which the +reason alone can attain to. Problems may be solved in the study +which have baffled all those who have sought a solution by the +aid of their senses. To carry the art, however, to its highest +pitch, it is necessary that the reasoner should be able to +utilise all the facts which have come to his knowledge; and this +in itself implies, as you will readily see, a possession of all +knowledge, which, even in these days of free education and +encyclopaedias, is a somewhat rare accomplishment. It is not so +impossible, however, that a man should possess all knowledge +which is likely to be useful to him in his work, and this I have +endeavoured in my case to do. If I remember rightly, you on one +occasion, in the early days of our friendship, defined my limits +in a very precise fashion." + +"Yes," I answered, laughing. "It was a singular document. +Philosophy, astronomy, and politics were marked at zero, I +remember. Botany variable, geology profound as regards the +mud-stains from any region within fifty miles of town, chemistry +eccentric, anatomy unsystematic, sensational literature and crime +records unique, violin-player, boxer, swordsman, lawyer, and +self-poisoner by cocaine and tobacco. Those, I think, were the +main points of my analysis." + +Holmes grinned at the last item. "Well," he said, "I say now, as +I said then, that a man should keep his little brain-attic +stocked with all the furniture that he is likely to use, and the +rest he can put away in the lumber-room of his library, where he +can get it if he wants it. Now, for such a case as the one which +has been submitted to us to-night, we need certainly to muster +all our resources. Kindly hand me down the letter K of the +'American Encyclopaedia' which stands upon the shelf beside you. +Thank you. Now let us consider the situation and see what may be +deduced from it. In the first place, we may start with a strong +presumption that Colonel Openshaw had some very strong reason for +leaving America. Men at his time of life do not change all their +habits and exchange willingly the charming climate of Florida for +the lonely life of an English provincial town. His extreme love +of solitude in England suggests the idea that he was in fear of +someone or something, so we may assume as a working hypothesis +that it was fear of someone or something which drove him from +America. As to what it was he feared, we can only deduce that by +considering the formidable letters which were received by himself +and his successors. Did you remark the postmarks of those +letters?" + +"The first was from Pondicherry, the second from Dundee, and the +third from London." + +"From East London. What do you deduce from that?" + +"They are all seaports. That the writer was on board of a ship." + +"Excellent. We have already a clue. There can be no doubt that +the probability--the strong probability--is that the writer was +on board of a ship. And now let us consider another point. In the +case of Pondicherry, seven weeks elapsed between the threat and +its fulfilment, in Dundee it was only some three or four days. +Does that suggest anything?" + +"A greater distance to travel." + +"But the letter had also a greater distance to come." + +"Then I do not see the point." + +"There is at least a presumption that the vessel in which the man +or men are is a sailing-ship. It looks as if they always send +their singular warning or token before them when starting upon +their mission. You see how quickly the deed followed the sign +when it came from Dundee. If they had come from Pondicherry in a +steamer they would have arrived almost as soon as their letter. +But, as a matter of fact, seven weeks elapsed. I think that those +seven weeks represented the difference between the mail-boat which +brought the letter and the sailing vessel which brought the +writer." + +"It is possible." + +"More than that. It is probable. And now you see the deadly +urgency of this new case, and why I urged young Openshaw to +caution. The blow has always fallen at the end of the time which +it would take the senders to travel the distance. But this one +comes from London, and therefore we cannot count upon delay." + +"Good God!" I cried. "What can it mean, this relentless +persecution?" + +"The papers which Openshaw carried are obviously of vital +importance to the person or persons in the sailing-ship. I think +that it is quite clear that there must be more than one of them. +A single man could not have carried out two deaths in such a way +as to deceive a coroner's jury. There must have been several in +it, and they must have been men of resource and determination. +Their papers they mean to have, be the holder of them who it may. +In this way you see K. K. K. ceases to be the initials of an +individual and becomes the badge of a society." + +"But of what society?" + +"Have you never--" said Sherlock Holmes, bending forward and +sinking his voice--"have you never heard of the Ku Klux Klan?" + +"I never have." + +Holmes turned over the leaves of the book upon his knee. "Here it +is," said he presently: + +"'Ku Klux Klan. A name derived from the fanciful resemblance to +the sound produced by cocking a rifle. This terrible secret +society was formed by some ex-Confederate soldiers in the +Southern states after the Civil War, and it rapidly formed local +branches in different parts of the country, notably in Tennessee, +Louisiana, the Carolinas, Georgia, and Florida. Its power was +used for political purposes, principally for the terrorising of +the negro voters and the murdering and driving from the country +of those who were opposed to its views. Its outrages were usually +preceded by a warning sent to the marked man in some fantastic +but generally recognised shape--a sprig of oak-leaves in some +parts, melon seeds or orange pips in others. On receiving this +the victim might either openly abjure his former ways, or might +fly from the country. If he braved the matter out, death would +unfailingly come upon him, and usually in some strange and +unforeseen manner. So perfect was the organisation of the +society, and so systematic its methods, that there is hardly a +case upon record where any man succeeded in braving it with +impunity, or in which any of its outrages were traced home to the +perpetrators. For some years the organisation flourished in spite +of the efforts of the United States government and of the better +classes of the community in the South. Eventually, in the year +1869, the movement rather suddenly collapsed, although there have +been sporadic outbreaks of the same sort since that date.' + +"You will observe," said Holmes, laying down the volume, "that +the sudden breaking up of the society was coincident with the +disappearance of Openshaw from America with their papers. It may +well have been cause and effect. It is no wonder that he and his +family have some of the more implacable spirits upon their track. +You can understand that this register and diary may implicate +some of the first men in the South, and that there may be many +who will not sleep easy at night until it is recovered." + +"Then the page we have seen--" + +"Is such as we might expect. It ran, if I remember right, 'sent +the pips to A, B, and C'--that is, sent the society's warning to +them. Then there are successive entries that A and B cleared, or +left the country, and finally that C was visited, with, I fear, a +sinister result for C. Well, I think, Doctor, that we may let +some light into this dark place, and I believe that the only +chance young Openshaw has in the meantime is to do what I have +told him. There is nothing more to be said or to be done +to-night, so hand me over my violin and let us try to forget for +half an hour the miserable weather and the still more miserable +ways of our fellow-men." + + +It had cleared in the morning, and the sun was shining with a +subdued brightness through the dim veil which hangs over the +great city. Sherlock Holmes was already at breakfast when I came +down. + +"You will excuse me for not waiting for you," said he; "I have, I +foresee, a very busy day before me in looking into this case of +young Openshaw's." + +"What steps will you take?" I asked. + +"It will very much depend upon the results of my first inquiries. +I may have to go down to Horsham, after all." + +"You will not go there first?" + +"No, I shall commence with the City. Just ring the bell and the +maid will bring up your coffee." + +As I waited, I lifted the unopened newspaper from the table and +glanced my eye over it. It rested upon a heading which sent a +chill to my heart. + +"Holmes," I cried, "you are too late." + +"Ah!" said he, laying down his cup, "I feared as much. How was it +done?" He spoke calmly, but I could see that he was deeply moved. + +"My eye caught the name of Openshaw, and the heading 'Tragedy +Near Waterloo Bridge.' Here is the account: + +"Between nine and ten last night Police-Constable Cook, of the H +Division, on duty near Waterloo Bridge, heard a cry for help and +a splash in the water. The night, however, was extremely dark and +stormy, so that, in spite of the help of several passers-by, it +was quite impossible to effect a rescue. The alarm, however, was +given, and, by the aid of the water-police, the body was +eventually recovered. It proved to be that of a young gentleman +whose name, as it appears from an envelope which was found in his +pocket, was John Openshaw, and whose residence is near Horsham. +It is conjectured that he may have been hurrying down to catch +the last train from Waterloo Station, and that in his haste and +the extreme darkness he missed his path and walked over the edge +of one of the small landing-places for river steamboats. The body +exhibited no traces of violence, and there can be no doubt that +the deceased had been the victim of an unfortunate accident, +which should have the effect of calling the attention of the +authorities to the condition of the riverside landing-stages." + +We sat in silence for some minutes, Holmes more depressed and +shaken than I had ever seen him. + +"That hurts my pride, Watson," he said at last. "It is a petty +feeling, no doubt, but it hurts my pride. It becomes a personal +matter with me now, and, if God sends me health, I shall set my +hand upon this gang. That he should come to me for help, and that +I should send him away to his death--!" He sprang from his chair +and paced about the room in uncontrollable agitation, with a +flush upon his sallow cheeks and a nervous clasping and +unclasping of his long thin hands. + +"They must be cunning devils," he exclaimed at last. "How could +they have decoyed him down there? The Embankment is not on the +direct line to the station. The bridge, no doubt, was too +crowded, even on such a night, for their purpose. Well, Watson, +we shall see who will win in the long run. I am going out now!" + +"To the police?" + +"No; I shall be my own police. When I have spun the web they may +take the flies, but not before." + +All day I was engaged in my professional work, and it was late in +the evening before I returned to Baker Street. Sherlock Holmes +had not come back yet. It was nearly ten o'clock before he +entered, looking pale and worn. He walked up to the sideboard, +and tearing a piece from the loaf he devoured it voraciously, +washing it down with a long draught of water. + +"You are hungry," I remarked. + +"Starving. It had escaped my memory. I have had nothing since +breakfast." + +"Nothing?" + +"Not a bite. I had no time to think of it." + +"And how have you succeeded?" + +"Well." + +"You have a clue?" + +"I have them in the hollow of my hand. Young Openshaw shall not +long remain unavenged. Why, Watson, let us put their own devilish +trade-mark upon them. It is well thought of!" + +"What do you mean?" + +He took an orange from the cupboard, and tearing it to pieces he +squeezed out the pips upon the table. Of these he took five and +thrust them into an envelope. On the inside of the flap he wrote +"S. H. for J. O." Then he sealed it and addressed it to "Captain +James Calhoun, Barque 'Lone Star,' Savannah, Georgia." + +"That will await him when he enters port," said he, chuckling. +"It may give him a sleepless night. He will find it as sure a +precursor of his fate as Openshaw did before him." + +"And who is this Captain Calhoun?" + +"The leader of the gang. I shall have the others, but he first." + +"How did you trace it, then?" + +He took a large sheet of paper from his pocket, all covered with +dates and names. + +"I have spent the whole day," said he, "over Lloyd's registers +and files of the old papers, following the future career of every +vessel which touched at Pondicherry in January and February in +'83. There were thirty-six ships of fair tonnage which were +reported there during those months. Of these, one, the 'Lone Star,' +instantly attracted my attention, since, although it was reported +as having cleared from London, the name is that which is given to +one of the states of the Union." + +"Texas, I think." + +"I was not and am not sure which; but I knew that the ship must +have an American origin." + +"What then?" + +"I searched the Dundee records, and when I found that the barque +'Lone Star' was there in January, '85, my suspicion became a +certainty. I then inquired as to the vessels which lay at present +in the port of London." + +"Yes?" + +"The 'Lone Star' had arrived here last week. I went down to the +Albert Dock and found that she had been taken down the river by +the early tide this morning, homeward bound to Savannah. I wired +to Gravesend and learned that she had passed some time ago, and +as the wind is easterly I have no doubt that she is now past the +Goodwins and not very far from the Isle of Wight." + +"What will you do, then?" + +"Oh, I have my hand upon him. He and the two mates, are as I +learn, the only native-born Americans in the ship. The others are +Finns and Germans. I know, also, that they were all three away +from the ship last night. I had it from the stevedore who has +been loading their cargo. By the time that their sailing-ship +reaches Savannah the mail-boat will have carried this letter, and +the cable will have informed the police of Savannah that these +three gentlemen are badly wanted here upon a charge of murder." + +There is ever a flaw, however, in the best laid of human plans, +and the murderers of John Openshaw were never to receive the +orange pips which would show them that another, as cunning and as +resolute as themselves, was upon their track. Very long and very +severe were the equinoctial gales that year. We waited long for +news of the "Lone Star" of Savannah, but none ever reached us. We +did at last hear that somewhere far out in the Atlantic a +shattered stern-post of a boat was seen swinging in the trough +of a wave, with the letters "L. S." carved upon it, and that is +all which we shall ever know of the fate of the "Lone Star." + + + +ADVENTURE VI. THE MAN WITH THE TWISTED LIP + +Isa Whitney, brother of the late Elias Whitney, D.D., Principal +of the Theological College of St. George's, was much addicted to +opium. The habit grew upon him, as I understand, from some +foolish freak when he was at college; for having read De +Quincey's description of his dreams and sensations, he had +drenched his tobacco with laudanum in an attempt to produce the +same effects. He found, as so many more have done, that the +practice is easier to attain than to get rid of, and for many +years he continued to be a slave to the drug, an object of +mingled horror and pity to his friends and relatives. I can see +him now, with yellow, pasty face, drooping lids, and pin-point +pupils, all huddled in a chair, the wreck and ruin of a noble +man. + +One night--it was in June, '89--there came a ring to my bell, +about the hour when a man gives his first yawn and glances at the +clock. I sat up in my chair, and my wife laid her needle-work +down in her lap and made a little face of disappointment. + +"A patient!" said she. "You'll have to go out." + +I groaned, for I was newly come back from a weary day. + +We heard the door open, a few hurried words, and then quick steps +upon the linoleum. Our own door flew open, and a lady, clad in +some dark-coloured stuff, with a black veil, entered the room. + +"You will excuse my calling so late," she began, and then, +suddenly losing her self-control, she ran forward, threw her arms +about my wife's neck, and sobbed upon her shoulder. "Oh, I'm in +such trouble!" she cried; "I do so want a little help." + +"Why," said my wife, pulling up her veil, "it is Kate Whitney. +How you startled me, Kate! I had not an idea who you were when +you came in." + +"I didn't know what to do, so I came straight to you." That was +always the way. Folk who were in grief came to my wife like birds +to a light-house. + +"It was very sweet of you to come. Now, you must have some wine +and water, and sit here comfortably and tell us all about it. Or +should you rather that I sent James off to bed?" + +"Oh, no, no! I want the doctor's advice and help, too. It's about +Isa. He has not been home for two days. I am so frightened about +him!" + +It was not the first time that she had spoken to us of her +husband's trouble, to me as a doctor, to my wife as an old friend +and school companion. We soothed and comforted her by such words +as we could find. Did she know where her husband was? Was it +possible that we could bring him back to her? + +It seems that it was. She had the surest information that of late +he had, when the fit was on him, made use of an opium den in the +farthest east of the City. Hitherto his orgies had always been +confined to one day, and he had come back, twitching and +shattered, in the evening. But now the spell had been upon him +eight-and-forty hours, and he lay there, doubtless among the +dregs of the docks, breathing in the poison or sleeping off the +effects. There he was to be found, she was sure of it, at the Bar +of Gold, in Upper Swandam Lane. But what was she to do? How could +she, a young and timid woman, make her way into such a place and +pluck her husband out from among the ruffians who surrounded him? + +There was the case, and of course there was but one way out of +it. Might I not escort her to this place? And then, as a second +thought, why should she come at all? I was Isa Whitney's medical +adviser, and as such I had influence over him. I could manage it +better if I were alone. I promised her on my word that I would +send him home in a cab within two hours if he were indeed at the +address which she had given me. And so in ten minutes I had left +my armchair and cheery sitting-room behind me, and was speeding +eastward in a hansom on a strange errand, as it seemed to me at +the time, though the future only could show how strange it was to +be. + +But there was no great difficulty in the first stage of my +adventure. Upper Swandam Lane is a vile alley lurking behind the +high wharves which line the north side of the river to the east +of London Bridge. Between a slop-shop and a gin-shop, approached +by a steep flight of steps leading down to a black gap like the +mouth of a cave, I found the den of which I was in search. +Ordering my cab to wait, I passed down the steps, worn hollow in +the centre by the ceaseless tread of drunken feet; and by the +light of a flickering oil-lamp above the door I found the latch +and made my way into a long, low room, thick and heavy with the +brown opium smoke, and terraced with wooden berths, like the +forecastle of an emigrant ship. + +Through the gloom one could dimly catch a glimpse of bodies lying +in strange fantastic poses, bowed shoulders, bent knees, heads +thrown back, and chins pointing upward, with here and there a +dark, lack-lustre eye turned upon the newcomer. Out of the black +shadows there glimmered little red circles of light, now bright, +now faint, as the burning poison waxed or waned in the bowls of +the metal pipes. The most lay silent, but some muttered to +themselves, and others talked together in a strange, low, +monotonous voice, their conversation coming in gushes, and then +suddenly tailing off into silence, each mumbling out his own +thoughts and paying little heed to the words of his neighbour. At +the farther end was a small brazier of burning charcoal, beside +which on a three-legged wooden stool there sat a tall, thin old +man, with his jaw resting upon his two fists, and his elbows upon +his knees, staring into the fire. + +As I entered, a sallow Malay attendant had hurried up with a pipe +for me and a supply of the drug, beckoning me to an empty berth. + +"Thank you. I have not come to stay," said I. "There is a friend +of mine here, Mr. Isa Whitney, and I wish to speak with him." + +There was a movement and an exclamation from my right, and +peering through the gloom, I saw Whitney, pale, haggard, and +unkempt, staring out at me. + +"My God! It's Watson," said he. He was in a pitiable state of +reaction, with every nerve in a twitter. "I say, Watson, what +o'clock is it?" + +"Nearly eleven." + +"Of what day?" + +"Of Friday, June 19th." + +"Good heavens! I thought it was Wednesday. It is Wednesday. What +d'you want to frighten a chap for?" He sank his face onto his +arms and began to sob in a high treble key. + +"I tell you that it is Friday, man. Your wife has been waiting +this two days for you. You should be ashamed of yourself!" + +"So I am. But you've got mixed, Watson, for I have only been here +a few hours, three pipes, four pipes--I forget how many. But I'll +go home with you. I wouldn't frighten Kate--poor little Kate. +Give me your hand! Have you a cab?" + +"Yes, I have one waiting." + +"Then I shall go in it. But I must owe something. Find what I +owe, Watson. I am all off colour. I can do nothing for myself." + +I walked down the narrow passage between the double row of +sleepers, holding my breath to keep out the vile, stupefying +fumes of the drug, and looking about for the manager. As I passed +the tall man who sat by the brazier I felt a sudden pluck at my +skirt, and a low voice whispered, "Walk past me, and then look +back at me." The words fell quite distinctly upon my ear. I +glanced down. They could only have come from the old man at my +side, and yet he sat now as absorbed as ever, very thin, very +wrinkled, bent with age, an opium pipe dangling down from between +his knees, as though it had dropped in sheer lassitude from his +fingers. I took two steps forward and looked back. It took all my +self-control to prevent me from breaking out into a cry of +astonishment. He had turned his back so that none could see him +but I. His form had filled out, his wrinkles were gone, the dull +eyes had regained their fire, and there, sitting by the fire and +grinning at my surprise, was none other than Sherlock Holmes. He +made a slight motion to me to approach him, and instantly, as he +turned his face half round to the company once more, subsided +into a doddering, loose-lipped senility. + +"Holmes!" I whispered, "what on earth are you doing in this den?" + +"As low as you can," he answered; "I have excellent ears. If you +would have the great kindness to get rid of that sottish friend +of yours I should be exceedingly glad to have a little talk with +you." + +"I have a cab outside." + +"Then pray send him home in it. You may safely trust him, for he +appears to be too limp to get into any mischief. I should +recommend you also to send a note by the cabman to your wife to +say that you have thrown in your lot with me. If you will wait +outside, I shall be with you in five minutes." + +It was difficult to refuse any of Sherlock Holmes' requests, for +they were always so exceedingly definite, and put forward with +such a quiet air of mastery. I felt, however, that when Whitney +was once confined in the cab my mission was practically +accomplished; and for the rest, I could not wish anything better +than to be associated with my friend in one of those singular +adventures which were the normal condition of his existence. In a +few minutes I had written my note, paid Whitney's bill, led him +out to the cab, and seen him driven through the darkness. In a +very short time a decrepit figure had emerged from the opium den, +and I was walking down the street with Sherlock Holmes. For two +streets he shuffled along with a bent back and an uncertain foot. +Then, glancing quickly round, he straightened himself out and +burst into a hearty fit of laughter. + +"I suppose, Watson," said he, "that you imagine that I have added +opium-smoking to cocaine injections, and all the other little +weaknesses on which you have favoured me with your medical +views." + +"I was certainly surprised to find you there." + +"But not more so than I to find you." + +"I came to find a friend." + +"And I to find an enemy." + +"An enemy?" + +"Yes; one of my natural enemies, or, shall I say, my natural +prey. Briefly, Watson, I am in the midst of a very remarkable +inquiry, and I have hoped to find a clue in the incoherent +ramblings of these sots, as I have done before now. Had I been +recognised in that den my life would not have been worth an +hour's purchase; for I have used it before now for my own +purposes, and the rascally Lascar who runs it has sworn to have +vengeance upon me. There is a trap-door at the back of that +building, near the corner of Paul's Wharf, which could tell some +strange tales of what has passed through it upon the moonless +nights." + +"What! You do not mean bodies?" + +"Ay, bodies, Watson. We should be rich men if we had 1000 pounds +for every poor devil who has been done to death in that den. It +is the vilest murder-trap on the whole riverside, and I fear that +Neville St. Clair has entered it never to leave it more. But our +trap should be here." He put his two forefingers between his +teeth and whistled shrilly--a signal which was answered by a +similar whistle from the distance, followed shortly by the rattle +of wheels and the clink of horses' hoofs. + +"Now, Watson," said Holmes, as a tall dog-cart dashed up through +the gloom, throwing out two golden tunnels of yellow light from +its side lanterns. "You'll come with me, won't you?" + +"If I can be of use." + +"Oh, a trusty comrade is always of use; and a chronicler still +more so. My room at The Cedars is a double-bedded one." + +"The Cedars?" + +"Yes; that is Mr. St. Clair's house. I am staying there while I +conduct the inquiry." + +"Where is it, then?" + +"Near Lee, in Kent. We have a seven-mile drive before us." + +"But I am all in the dark." + +"Of course you are. You'll know all about it presently. Jump up +here. All right, John; we shall not need you. Here's half a +crown. Look out for me to-morrow, about eleven. Give her her +head. So long, then!" + +He flicked the horse with his whip, and we dashed away through +the endless succession of sombre and deserted streets, which +widened gradually, until we were flying across a broad +balustraded bridge, with the murky river flowing sluggishly +beneath us. Beyond lay another dull wilderness of bricks and +mortar, its silence broken only by the heavy, regular footfall of +the policeman, or the songs and shouts of some belated party of +revellers. A dull wrack was drifting slowly across the sky, and a +star or two twinkled dimly here and there through the rifts of +the clouds. Holmes drove in silence, with his head sunk upon his +breast, and the air of a man who is lost in thought, while I sat +beside him, curious to learn what this new quest might be which +seemed to tax his powers so sorely, and yet afraid to break in +upon the current of his thoughts. We had driven several miles, +and were beginning to get to the fringe of the belt of suburban +villas, when he shook himself, shrugged his shoulders, and lit up +his pipe with the air of a man who has satisfied himself that he +is acting for the best. + +"You have a grand gift of silence, Watson," said he. "It makes +you quite invaluable as a companion. 'Pon my word, it is a great +thing for me to have someone to talk to, for my own thoughts are +not over-pleasant. I was wondering what I should say to this dear +little woman to-night when she meets me at the door." + +"You forget that I know nothing about it." + +"I shall just have time to tell you the facts of the case before +we get to Lee. It seems absurdly simple, and yet, somehow I can +get nothing to go upon. There's plenty of thread, no doubt, but I +can't get the end of it into my hand. Now, I'll state the case +clearly and concisely to you, Watson, and maybe you can see a +spark where all is dark to me." + +"Proceed, then." + +"Some years ago--to be definite, in May, 1884--there came to Lee +a gentleman, Neville St. Clair by name, who appeared to have +plenty of money. He took a large villa, laid out the grounds very +nicely, and lived generally in good style. By degrees he made +friends in the neighbourhood, and in 1887 he married the daughter +of a local brewer, by whom he now has two children. He had no +occupation, but was interested in several companies and went into +town as a rule in the morning, returning by the 5:14 from Cannon +Street every night. Mr. St. Clair is now thirty-seven years of +age, is a man of temperate habits, a good husband, a very +affectionate father, and a man who is popular with all who know +him. I may add that his whole debts at the present moment, as far +as we have been able to ascertain, amount to 88 pounds 10s., while +he has 220 pounds standing to his credit in the Capital and +Counties Bank. There is no reason, therefore, to think that money +troubles have been weighing upon his mind. + +"Last Monday Mr. Neville St. Clair went into town rather earlier +than usual, remarking before he started that he had two important +commissions to perform, and that he would bring his little boy +home a box of bricks. Now, by the merest chance, his wife +received a telegram upon this same Monday, very shortly after his +departure, to the effect that a small parcel of considerable +value which she had been expecting was waiting for her at the +offices of the Aberdeen Shipping Company. Now, if you are well up +in your London, you will know that the office of the company is +in Fresno Street, which branches out of Upper Swandam Lane, where +you found me to-night. Mrs. St. Clair had her lunch, started for +the City, did some shopping, proceeded to the company's office, +got her packet, and found herself at exactly 4:35 walking through +Swandam Lane on her way back to the station. Have you followed me +so far?" + +"It is very clear." + +"If you remember, Monday was an exceedingly hot day, and Mrs. St. +Clair walked slowly, glancing about in the hope of seeing a cab, +as she did not like the neighbourhood in which she found herself. +While she was walking in this way down Swandam Lane, she suddenly +heard an ejaculation or cry, and was struck cold to see her +husband looking down at her and, as it seemed to her, beckoning +to her from a second-floor window. The window was open, and she +distinctly saw his face, which she describes as being terribly +agitated. He waved his hands frantically to her, and then +vanished from the window so suddenly that it seemed to her that +he had been plucked back by some irresistible force from behind. +One singular point which struck her quick feminine eye was that +although he wore some dark coat, such as he had started to town +in, he had on neither collar nor necktie. + +"Convinced that something was amiss with him, she rushed down the +steps--for the house was none other than the opium den in which +you found me to-night--and running through the front room she +attempted to ascend the stairs which led to the first floor. At +the foot of the stairs, however, she met this Lascar scoundrel of +whom I have spoken, who thrust her back and, aided by a Dane, who +acts as assistant there, pushed her out into the street. Filled +with the most maddening doubts and fears, she rushed down the +lane and, by rare good-fortune, met in Fresno Street a number of +constables with an inspector, all on their way to their beat. The +inspector and two men accompanied her back, and in spite of the +continued resistance of the proprietor, they made their way to +the room in which Mr. St. Clair had last been seen. There was no +sign of him there. In fact, in the whole of that floor there was +no one to be found save a crippled wretch of hideous aspect, who, +it seems, made his home there. Both he and the Lascar stoutly +swore that no one else had been in the front room during the +afternoon. So determined was their denial that the inspector was +staggered, and had almost come to believe that Mrs. St. Clair had +been deluded when, with a cry, she sprang at a small deal box +which lay upon the table and tore the lid from it. Out there fell +a cascade of children's bricks. It was the toy which he had +promised to bring home. + +"This discovery, and the evident confusion which the cripple +showed, made the inspector realise that the matter was serious. +The rooms were carefully examined, and results all pointed to an +abominable crime. The front room was plainly furnished as a +sitting-room and led into a small bedroom, which looked out upon +the back of one of the wharves. Between the wharf and the bedroom +window is a narrow strip, which is dry at low tide but is covered +at high tide with at least four and a half feet of water. The +bedroom window was a broad one and opened from below. On +examination traces of blood were to be seen upon the windowsill, +and several scattered drops were visible upon the wooden floor of +the bedroom. Thrust away behind a curtain in the front room were +all the clothes of Mr. Neville St. Clair, with the exception of +his coat. His boots, his socks, his hat, and his watch--all were +there. There were no signs of violence upon any of these +garments, and there were no other traces of Mr. Neville St. +Clair. Out of the window he must apparently have gone for no +other exit could be discovered, and the ominous bloodstains upon +the sill gave little promise that he could save himself by +swimming, for the tide was at its very highest at the moment of +the tragedy. + +"And now as to the villains who seemed to be immediately +implicated in the matter. The Lascar was known to be a man of the +vilest antecedents, but as, by Mrs. St. Clair's story, he was +known to have been at the foot of the stair within a very few +seconds of her husband's appearance at the window, he could +hardly have been more than an accessory to the crime. His defence +was one of absolute ignorance, and he protested that he had no +knowledge as to the doings of Hugh Boone, his lodger, and that he +could not account in any way for the presence of the missing +gentleman's clothes. + +"So much for the Lascar manager. Now for the sinister cripple who +lives upon the second floor of the opium den, and who was +certainly the last human being whose eyes rested upon Neville St. +Clair. His name is Hugh Boone, and his hideous face is one which +is familiar to every man who goes much to the City. He is a +professional beggar, though in order to avoid the police +regulations he pretends to a small trade in wax vestas. Some +little distance down Threadneedle Street, upon the left-hand +side, there is, as you may have remarked, a small angle in the +wall. Here it is that this creature takes his daily seat, +cross-legged with his tiny stock of matches on his lap, and as he +is a piteous spectacle a small rain of charity descends into the +greasy leather cap which lies upon the pavement beside him. I +have watched the fellow more than once before ever I thought of +making his professional acquaintance, and I have been surprised +at the harvest which he has reaped in a short time. His +appearance, you see, is so remarkable that no one can pass him +without observing him. A shock of orange hair, a pale face +disfigured by a horrible scar, which, by its contraction, has +turned up the outer edge of his upper lip, a bulldog chin, and a +pair of very penetrating dark eyes, which present a singular +contrast to the colour of his hair, all mark him out from amid +the common crowd of mendicants and so, too, does his wit, for he +is ever ready with a reply to any piece of chaff which may be +thrown at him by the passers-by. This is the man whom we now +learn to have been the lodger at the opium den, and to have been +the last man to see the gentleman of whom we are in quest." + +"But a cripple!" said I. "What could he have done single-handed +against a man in the prime of life?" + +"He is a cripple in the sense that he walks with a limp; but in +other respects he appears to be a powerful and well-nurtured man. +Surely your medical experience would tell you, Watson, that +weakness in one limb is often compensated for by exceptional +strength in the others." + +"Pray continue your narrative." + +"Mrs. St. Clair had fainted at the sight of the blood upon the +window, and she was escorted home in a cab by the police, as her +presence could be of no help to them in their investigations. +Inspector Barton, who had charge of the case, made a very careful +examination of the premises, but without finding anything which +threw any light upon the matter. One mistake had been made in not +arresting Boone instantly, as he was allowed some few minutes +during which he might have communicated with his friend the +Lascar, but this fault was soon remedied, and he was seized and +searched, without anything being found which could incriminate +him. There were, it is true, some blood-stains upon his right +shirt-sleeve, but he pointed to his ring-finger, which had been +cut near the nail, and explained that the bleeding came from +there, adding that he had been to the window not long before, and +that the stains which had been observed there came doubtless from +the same source. He denied strenuously having ever seen Mr. +Neville St. Clair and swore that the presence of the clothes in +his room was as much a mystery to him as to the police. As to +Mrs. St. Clair's assertion that she had actually seen her husband +at the window, he declared that she must have been either mad or +dreaming. He was removed, loudly protesting, to the +police-station, while the inspector remained upon the premises in +the hope that the ebbing tide might afford some fresh clue. + +"And it did, though they hardly found upon the mud-bank what they +had feared to find. It was Neville St. Clair's coat, and not +Neville St. Clair, which lay uncovered as the tide receded. And +what do you think they found in the pockets?" + +"I cannot imagine." + +"No, I don't think you would guess. Every pocket stuffed with +pennies and half-pennies--421 pennies and 270 half-pennies. It +was no wonder that it had not been swept away by the tide. But a +human body is a different matter. There is a fierce eddy between +the wharf and the house. It seemed likely enough that the +weighted coat had remained when the stripped body had been sucked +away into the river." + +"But I understand that all the other clothes were found in the +room. Would the body be dressed in a coat alone?" + +"No, sir, but the facts might be met speciously enough. Suppose +that this man Boone had thrust Neville St. Clair through the +window, there is no human eye which could have seen the deed. +What would he do then? It would of course instantly strike him +that he must get rid of the tell-tale garments. He would seize +the coat, then, and be in the act of throwing it out, when it +would occur to him that it would swim and not sink. He has little +time, for he has heard the scuffle downstairs when the wife tried +to force her way up, and perhaps he has already heard from his +Lascar confederate that the police are hurrying up the street. +There is not an instant to be lost. He rushes to some secret +hoard, where he has accumulated the fruits of his beggary, and he +stuffs all the coins upon which he can lay his hands into the +pockets to make sure of the coat's sinking. He throws it out, and +would have done the same with the other garments had not he heard +the rush of steps below, and only just had time to close the +window when the police appeared." + +"It certainly sounds feasible." + +"Well, we will take it as a working hypothesis for want of a +better. Boone, as I have told you, was arrested and taken to the +station, but it could not be shown that there had ever before +been anything against him. He had for years been known as a +professional beggar, but his life appeared to have been a very +quiet and innocent one. There the matter stands at present, and +the questions which have to be solved--what Neville St. Clair was +doing in the opium den, what happened to him when there, where is +he now, and what Hugh Boone had to do with his disappearance--are +all as far from a solution as ever. I confess that I cannot +recall any case within my experience which looked at the first +glance so simple and yet which presented such difficulties." + +While Sherlock Holmes had been detailing this singular series of +events, we had been whirling through the outskirts of the great +town until the last straggling houses had been left behind, and +we rattled along with a country hedge upon either side of us. +Just as he finished, however, we drove through two scattered +villages, where a few lights still glimmered in the windows. + +"We are on the outskirts of Lee," said my companion. "We have +touched on three English counties in our short drive, starting in +Middlesex, passing over an angle of Surrey, and ending in Kent. +See that light among the trees? That is The Cedars, and beside +that lamp sits a woman whose anxious ears have already, I have +little doubt, caught the clink of our horse's feet." + +"But why are you not conducting the case from Baker Street?" I +asked. + +"Because there are many inquiries which must be made out here. +Mrs. St. Clair has most kindly put two rooms at my disposal, and +you may rest assured that she will have nothing but a welcome for +my friend and colleague. I hate to meet her, Watson, when I have +no news of her husband. Here we are. Whoa, there, whoa!" + +We had pulled up in front of a large villa which stood within its +own grounds. A stable-boy had run out to the horse's head, and +springing down, I followed Holmes up the small, winding +gravel-drive which led to the house. As we approached, the door +flew open, and a little blonde woman stood in the opening, clad +in some sort of light mousseline de soie, with a touch of fluffy +pink chiffon at her neck and wrists. She stood with her figure +outlined against the flood of light, one hand upon the door, one +half-raised in her eagerness, her body slightly bent, her head +and face protruded, with eager eyes and parted lips, a standing +question. + +"Well?" she cried, "well?" And then, seeing that there were two +of us, she gave a cry of hope which sank into a groan as she saw +that my companion shook his head and shrugged his shoulders. + +"No good news?" + +"None." + +"No bad?" + +"No." + +"Thank God for that. But come in. You must be weary, for you have +had a long day." + +"This is my friend, Dr. Watson. He has been of most vital use to +me in several of my cases, and a lucky chance has made it +possible for me to bring him out and associate him with this +investigation." + +"I am delighted to see you," said she, pressing my hand warmly. +"You will, I am sure, forgive anything that may be wanting in our +arrangements, when you consider the blow which has come so +suddenly upon us." + +"My dear madam," said I, "I am an old campaigner, and if I were +not I can very well see that no apology is needed. If I can be of +any assistance, either to you or to my friend here, I shall be +indeed happy." + +"Now, Mr. Sherlock Holmes," said the lady as we entered a +well-lit dining-room, upon the table of which a cold supper had +been laid out, "I should very much like to ask you one or two +plain questions, to which I beg that you will give a plain +answer." + +"Certainly, madam." + +"Do not trouble about my feelings. I am not hysterical, nor given +to fainting. I simply wish to hear your real, real opinion." + +"Upon what point?" + +"In your heart of hearts, do you think that Neville is alive?" + +Sherlock Holmes seemed to be embarrassed by the question. +"Frankly, now!" she repeated, standing upon the rug and looking +keenly down at him as he leaned back in a basket-chair. + +"Frankly, then, madam, I do not." + +"You think that he is dead?" + +"I do." + +"Murdered?" + +"I don't say that. Perhaps." + +"And on what day did he meet his death?" + +"On Monday." + +"Then perhaps, Mr. Holmes, you will be good enough to explain how +it is that I have received a letter from him to-day." + +Sherlock Holmes sprang out of his chair as if he had been +galvanised. + +"What!" he roared. + +"Yes, to-day." She stood smiling, holding up a little slip of +paper in the air. + +"May I see it?" + +"Certainly." + +He snatched it from her in his eagerness, and smoothing it out +upon the table he drew over the lamp and examined it intently. I +had left my chair and was gazing at it over his shoulder. The +envelope was a very coarse one and was stamped with the Gravesend +postmark and with the date of that very day, or rather of the day +before, for it was considerably after midnight. + +"Coarse writing," murmured Holmes. "Surely this is not your +husband's writing, madam." + +"No, but the enclosure is." + +"I perceive also that whoever addressed the envelope had to go +and inquire as to the address." + +"How can you tell that?" + +"The name, you see, is in perfectly black ink, which has dried +itself. The rest is of the greyish colour, which shows that +blotting-paper has been used. If it had been written straight +off, and then blotted, none would be of a deep black shade. This +man has written the name, and there has then been a pause before +he wrote the address, which can only mean that he was not +familiar with it. It is, of course, a trifle, but there is +nothing so important as trifles. Let us now see the letter. Ha! +there has been an enclosure here!" + +"Yes, there was a ring. His signet-ring." + +"And you are sure that this is your husband's hand?" + +"One of his hands." + +"One?" + +"His hand when he wrote hurriedly. It is very unlike his usual +writing, and yet I know it well." + +"'Dearest do not be frightened. All will come well. There is a +huge error which it may take some little time to rectify. +Wait in patience.--NEVILLE.' Written in pencil upon the fly-leaf +of a book, octavo size, no water-mark. Hum! Posted to-day in +Gravesend by a man with a dirty thumb. Ha! And the flap has been +gummed, if I am not very much in error, by a person who had been +chewing tobacco. And you have no doubt that it is your husband's +hand, madam?" + +"None. Neville wrote those words." + +"And they were posted to-day at Gravesend. Well, Mrs. St. Clair, +the clouds lighten, though I should not venture to say that the +danger is over." + +"But he must be alive, Mr. Holmes." + +"Unless this is a clever forgery to put us on the wrong scent. +The ring, after all, proves nothing. It may have been taken from +him." + +"No, no; it is, it is his very own writing!" + +"Very well. It may, however, have been written on Monday and only +posted to-day." + +"That is possible." + +"If so, much may have happened between." + +"Oh, you must not discourage me, Mr. Holmes. I know that all is +well with him. There is so keen a sympathy between us that I +should know if evil came upon him. On the very day that I saw him +last he cut himself in the bedroom, and yet I in the dining-room +rushed upstairs instantly with the utmost certainty that +something had happened. Do you think that I would respond to such +a trifle and yet be ignorant of his death?" + +"I have seen too much not to know that the impression of a woman +may be more valuable than the conclusion of an analytical +reasoner. And in this letter you certainly have a very strong +piece of evidence to corroborate your view. But if your husband +is alive and able to write letters, why should he remain away +from you?" + +"I cannot imagine. It is unthinkable." + +"And on Monday he made no remarks before leaving you?" + +"No." + +"And you were surprised to see him in Swandam Lane?" + +"Very much so." + +"Was the window open?" + +"Yes." + +"Then he might have called to you?" + +"He might." + +"He only, as I understand, gave an inarticulate cry?" + +"Yes." + +"A call for help, you thought?" + +"Yes. He waved his hands." + +"But it might have been a cry of surprise. Astonishment at the +unexpected sight of you might cause him to throw up his hands?" + +"It is possible." + +"And you thought he was pulled back?" + +"He disappeared so suddenly." + +"He might have leaped back. You did not see anyone else in the +room?" + +"No, but this horrible man confessed to having been there, and +the Lascar was at the foot of the stairs." + +"Quite so. Your husband, as far as you could see, had his +ordinary clothes on?" + +"But without his collar or tie. I distinctly saw his bare +throat." + +"Had he ever spoken of Swandam Lane?" + +"Never." + +"Had he ever showed any signs of having taken opium?" + +"Never." + +"Thank you, Mrs. St. Clair. Those are the principal points about +which I wished to be absolutely clear. We shall now have a little +supper and then retire, for we may have a very busy day +to-morrow." + +A large and comfortable double-bedded room had been placed at our +disposal, and I was quickly between the sheets, for I was weary +after my night of adventure. Sherlock Holmes was a man, however, +who, when he had an unsolved problem upon his mind, would go for +days, and even for a week, without rest, turning it over, +rearranging his facts, looking at it from every point of view +until he had either fathomed it or convinced himself that his +data were insufficient. It was soon evident to me that he was now +preparing for an all-night sitting. He took off his coat and +waistcoat, put on a large blue dressing-gown, and then wandered +about the room collecting pillows from his bed and cushions from +the sofa and armchairs. With these he constructed a sort of +Eastern divan, upon which he perched himself cross-legged, with +an ounce of shag tobacco and a box of matches laid out in front +of him. In the dim light of the lamp I saw him sitting there, an +old briar pipe between his lips, his eyes fixed vacantly upon the +corner of the ceiling, the blue smoke curling up from him, +silent, motionless, with the light shining upon his strong-set +aquiline features. So he sat as I dropped off to sleep, and so he +sat when a sudden ejaculation caused me to wake up, and I found +the summer sun shining into the apartment. The pipe was still +between his lips, the smoke still curled upward, and the room was +full of a dense tobacco haze, but nothing remained of the heap of +shag which I had seen upon the previous night. + +"Awake, Watson?" he asked. + +"Yes." + +"Game for a morning drive?" + +"Certainly." + +"Then dress. No one is stirring yet, but I know where the +stable-boy sleeps, and we shall soon have the trap out." He +chuckled to himself as he spoke, his eyes twinkled, and he seemed +a different man to the sombre thinker of the previous night. + +As I dressed I glanced at my watch. It was no wonder that no one +was stirring. It was twenty-five minutes past four. I had hardly +finished when Holmes returned with the news that the boy was +putting in the horse. + +"I want to test a little theory of mine," said he, pulling on his +boots. "I think, Watson, that you are now standing in the +presence of one of the most absolute fools in Europe. I deserve +to be kicked from here to Charing Cross. But I think I have the +key of the affair now." + +"And where is it?" I asked, smiling. + +"In the bathroom," he answered. "Oh, yes, I am not joking," he +continued, seeing my look of incredulity. "I have just been +there, and I have taken it out, and I have got it in this +Gladstone bag. Come on, my boy, and we shall see whether it will +not fit the lock." + +We made our way downstairs as quietly as possible, and out into +the bright morning sunshine. In the road stood our horse and +trap, with the half-clad stable-boy waiting at the head. We both +sprang in, and away we dashed down the London Road. A few country +carts were stirring, bearing in vegetables to the metropolis, but +the lines of villas on either side were as silent and lifeless as +some city in a dream. + +"It has been in some points a singular case," said Holmes, +flicking the horse on into a gallop. "I confess that I have been +as blind as a mole, but it is better to learn wisdom late than +never to learn it at all." + +In town the earliest risers were just beginning to look sleepily +from their windows as we drove through the streets of the Surrey +side. Passing down the Waterloo Bridge Road we crossed over the +river, and dashing up Wellington Street wheeled sharply to the +right and found ourselves in Bow Street. Sherlock Holmes was well +known to the force, and the two constables at the door saluted +him. One of them held the horse's head while the other led us in. + +"Who is on duty?" asked Holmes. + +"Inspector Bradstreet, sir." + +"Ah, Bradstreet, how are you?" A tall, stout official had come +down the stone-flagged passage, in a peaked cap and frogged +jacket. "I wish to have a quiet word with you, Bradstreet." +"Certainly, Mr. Holmes. Step into my room here." It was a small, +office-like room, with a huge ledger upon the table, and a +telephone projecting from the wall. The inspector sat down at his +desk. + +"What can I do for you, Mr. Holmes?" + +"I called about that beggarman, Boone--the one who was charged +with being concerned in the disappearance of Mr. Neville St. +Clair, of Lee." + +"Yes. He was brought up and remanded for further inquiries." + +"So I heard. You have him here?" + +"In the cells." + +"Is he quiet?" + +"Oh, he gives no trouble. But he is a dirty scoundrel." + +"Dirty?" + +"Yes, it is all we can do to make him wash his hands, and his +face is as black as a tinker's. Well, when once his case has been +settled, he will have a regular prison bath; and I think, if you +saw him, you would agree with me that he needed it." + +"I should like to see him very much." + +"Would you? That is easily done. Come this way. You can leave +your bag." + +"No, I think that I'll take it." + +"Very good. Come this way, if you please." He led us down a +passage, opened a barred door, passed down a winding stair, and +brought us to a whitewashed corridor with a line of doors on each +side. + +"The third on the right is his," said the inspector. "Here it +is!" He quietly shot back a panel in the upper part of the door +and glanced through. + +"He is asleep," said he. "You can see him very well." + +We both put our eyes to the grating. The prisoner lay with his +face towards us, in a very deep sleep, breathing slowly and +heavily. He was a middle-sized man, coarsely clad as became his +calling, with a coloured shirt protruding through the rent in his +tattered coat. He was, as the inspector had said, extremely +dirty, but the grime which covered his face could not conceal its +repulsive ugliness. A broad wheal from an old scar ran right +across it from eye to chin, and by its contraction had turned up +one side of the upper lip, so that three teeth were exposed in a +perpetual snarl. A shock of very bright red hair grew low over +his eyes and forehead. + +"He's a beauty, isn't he?" said the inspector. + +"He certainly needs a wash," remarked Holmes. "I had an idea that +he might, and I took the liberty of bringing the tools with me." +He opened the Gladstone bag as he spoke, and took out, to my +astonishment, a very large bath-sponge. + +"He! he! You are a funny one," chuckled the inspector. + +"Now, if you will have the great goodness to open that door very +quietly, we will soon make him cut a much more respectable +figure." + +"Well, I don't know why not," said the inspector. "He doesn't +look a credit to the Bow Street cells, does he?" He slipped his +key into the lock, and we all very quietly entered the cell. The +sleeper half turned, and then settled down once more into a deep +slumber. Holmes stooped to the water-jug, moistened his sponge, +and then rubbed it twice vigorously across and down the +prisoner's face. + +"Let me introduce you," he shouted, "to Mr. Neville St. Clair, of +Lee, in the county of Kent." + +Never in my life have I seen such a sight. The man's face peeled +off under the sponge like the bark from a tree. Gone was the +coarse brown tint! Gone, too, was the horrid scar which had +seamed it across, and the twisted lip which had given the +repulsive sneer to the face! A twitch brought away the tangled +red hair, and there, sitting up in his bed, was a pale, +sad-faced, refined-looking man, black-haired and smooth-skinned, +rubbing his eyes and staring about him with sleepy bewilderment. +Then suddenly realising the exposure, he broke into a scream and +threw himself down with his face to the pillow. + +"Great heavens!" cried the inspector, "it is, indeed, the missing +man. I know him from the photograph." + +The prisoner turned with the reckless air of a man who abandons +himself to his destiny. "Be it so," said he. "And pray what am I +charged with?" + +"With making away with Mr. Neville St.-- Oh, come, you can't be +charged with that unless they make a case of attempted suicide of +it," said the inspector with a grin. "Well, I have been +twenty-seven years in the force, but this really takes the cake." + +"If I am Mr. Neville St. Clair, then it is obvious that no crime +has been committed, and that, therefore, I am illegally +detained." + +"No crime, but a very great error has been committed," said +Holmes. "You would have done better to have trusted your wife." + +"It was not the wife; it was the children," groaned the prisoner. +"God help me, I would not have them ashamed of their father. My +God! What an exposure! What can I do?" + +Sherlock Holmes sat down beside him on the couch and patted him +kindly on the shoulder. + +"If you leave it to a court of law to clear the matter up," said +he, "of course you can hardly avoid publicity. On the other hand, +if you convince the police authorities that there is no possible +case against you, I do not know that there is any reason that the +details should find their way into the papers. Inspector +Bradstreet would, I am sure, make notes upon anything which you +might tell us and submit it to the proper authorities. The case +would then never go into court at all." + +"God bless you!" cried the prisoner passionately. "I would have +endured imprisonment, ay, even execution, rather than have left +my miserable secret as a family blot to my children. + +"You are the first who have ever heard my story. My father was a +schoolmaster in Chesterfield, where I received an excellent +education. I travelled in my youth, took to the stage, and +finally became a reporter on an evening paper in London. One day +my editor wished to have a series of articles upon begging in the +metropolis, and I volunteered to supply them. There was the point +from which all my adventures started. It was only by trying +begging as an amateur that I could get the facts upon which to +base my articles. When an actor I had, of course, learned all the +secrets of making up, and had been famous in the green-room for +my skill. I took advantage now of my attainments. I painted my +face, and to make myself as pitiable as possible I made a good +scar and fixed one side of my lip in a twist by the aid of a +small slip of flesh-coloured plaster. Then with a red head of +hair, and an appropriate dress, I took my station in the business +part of the city, ostensibly as a match-seller but really as a +beggar. For seven hours I plied my trade, and when I returned +home in the evening I found to my surprise that I had received no +less than 26s. 4d. + +"I wrote my articles and thought little more of the matter until, +some time later, I backed a bill for a friend and had a writ +served upon me for 25 pounds. I was at my wit's end where to get +the money, but a sudden idea came to me. I begged a fortnight's +grace from the creditor, asked for a holiday from my employers, +and spent the time in begging in the City under my disguise. In +ten days I had the money and had paid the debt. + +"Well, you can imagine how hard it was to settle down to arduous +work at 2 pounds a week when I knew that I could earn as much in +a day by smearing my face with a little paint, laying my cap on +the ground, and sitting still. It was a long fight between my +pride and the money, but the dollars won at last, and I threw up +reporting and sat day after day in the corner which I had first +chosen, inspiring pity by my ghastly face and filling my pockets +with coppers. Only one man knew my secret. He was the keeper of a +low den in which I used to lodge in Swandam Lane, where I could +every morning emerge as a squalid beggar and in the evenings +transform myself into a well-dressed man about town. This fellow, +a Lascar, was well paid by me for his rooms, so that I knew that +my secret was safe in his possession. + +"Well, very soon I found that I was saving considerable sums of +money. I do not mean that any beggar in the streets of London +could earn 700 pounds a year--which is less than my average +takings--but I had exceptional advantages in my power of making +up, and also in a facility of repartee, which improved by +practice and made me quite a recognised character in the City. +All day a stream of pennies, varied by silver, poured in upon me, +and it was a very bad day in which I failed to take 2 pounds. + +"As I grew richer I grew more ambitious, took a house in the +country, and eventually married, without anyone having a +suspicion as to my real occupation. My dear wife knew that I had +business in the City. She little knew what. + +"Last Monday I had finished for the day and was dressing in my +room above the opium den when I looked out of my window and saw, +to my horror and astonishment, that my wife was standing in the +street, with her eyes fixed full upon me. I gave a cry of +surprise, threw up my arms to cover my face, and, rushing to my +confidant, the Lascar, entreated him to prevent anyone from +coming up to me. I heard her voice downstairs, but I knew that +she could not ascend. Swiftly I threw off my clothes, pulled on +those of a beggar, and put on my pigments and wig. Even a wife's +eyes could not pierce so complete a disguise. But then it +occurred to me that there might be a search in the room, and that +the clothes might betray me. I threw open the window, reopening +by my violence a small cut which I had inflicted upon myself in +the bedroom that morning. Then I seized my coat, which was +weighted by the coppers which I had just transferred to it from +the leather bag in which I carried my takings. I hurled it out of +the window, and it disappeared into the Thames. The other clothes +would have followed, but at that moment there was a rush of +constables up the stair, and a few minutes after I found, rather, +I confess, to my relief, that instead of being identified as Mr. +Neville St. Clair, I was arrested as his murderer. + +"I do not know that there is anything else for me to explain. I +was determined to preserve my disguise as long as possible, and +hence my preference for a dirty face. Knowing that my wife would +be terribly anxious, I slipped off my ring and confided it to the +Lascar at a moment when no constable was watching me, together +with a hurried scrawl, telling her that she had no cause to +fear." + +"That note only reached her yesterday," said Holmes. + +"Good God! What a week she must have spent!" + +"The police have watched this Lascar," said Inspector Bradstreet, +"and I can quite understand that he might find it difficult to +post a letter unobserved. Probably he handed it to some sailor +customer of his, who forgot all about it for some days." + +"That was it," said Holmes, nodding approvingly; "I have no doubt +of it. But have you never been prosecuted for begging?" + +"Many times; but what was a fine to me?" + +"It must stop here, however," said Bradstreet. "If the police are +to hush this thing up, there must be no more of Hugh Boone." + +"I have sworn it by the most solemn oaths which a man can take." + +"In that case I think that it is probable that no further steps +may be taken. But if you are found again, then all must come out. +I am sure, Mr. Holmes, that we are very much indebted to you for +having cleared the matter up. I wish I knew how you reach your +results." + +"I reached this one," said my friend, "by sitting upon five +pillows and consuming an ounce of shag. I think, Watson, that if +we drive to Baker Street we shall just be in time for breakfast." + + + +VII. THE ADVENTURE OF THE BLUE CARBUNCLE + +I had called upon my friend Sherlock Holmes upon the second +morning after Christmas, with the intention of wishing him the +compliments of the season. He was lounging upon the sofa in a +purple dressing-gown, a pipe-rack within his reach upon the +right, and a pile of crumpled morning papers, evidently newly +studied, near at hand. Beside the couch was a wooden chair, and +on the angle of the back hung a very seedy and disreputable +hard-felt hat, much the worse for wear, and cracked in several +places. A lens and a forceps lying upon the seat of the chair +suggested that the hat had been suspended in this manner for the +purpose of examination. + +"You are engaged," said I; "perhaps I interrupt you." + +"Not at all. I am glad to have a friend with whom I can discuss +my results. The matter is a perfectly trivial one"--he jerked his +thumb in the direction of the old hat--"but there are points in +connection with it which are not entirely devoid of interest and +even of instruction." + +I seated myself in his armchair and warmed my hands before his +crackling fire, for a sharp frost had set in, and the windows +were thick with the ice crystals. "I suppose," I remarked, "that, +homely as it looks, this thing has some deadly story linked on to +it--that it is the clue which will guide you in the solution of +some mystery and the punishment of some crime." + +"No, no. No crime," said Sherlock Holmes, laughing. "Only one of +those whimsical little incidents which will happen when you have +four million human beings all jostling each other within the +space of a few square miles. Amid the action and reaction of so +dense a swarm of humanity, every possible combination of events +may be expected to take place, and many a little problem will be +presented which may be striking and bizarre without being +criminal. We have already had experience of such." + +"So much so," I remarked, "that of the last six cases which I +have added to my notes, three have been entirely free of any +legal crime." + +"Precisely. You allude to my attempt to recover the Irene Adler +papers, to the singular case of Miss Mary Sutherland, and to the +adventure of the man with the twisted lip. Well, I have no doubt +that this small matter will fall into the same innocent category. +You know Peterson, the commissionaire?" + +"Yes." + +"It is to him that this trophy belongs." + +"It is his hat." + +"No, no, he found it. Its owner is unknown. I beg that you will +look upon it not as a battered billycock but as an intellectual +problem. And, first, as to how it came here. It arrived upon +Christmas morning, in company with a good fat goose, which is, I +have no doubt, roasting at this moment in front of Peterson's +fire. The facts are these: about four o'clock on Christmas +morning, Peterson, who, as you know, is a very honest fellow, was +returning from some small jollification and was making his way +homeward down Tottenham Court Road. In front of him he saw, in +the gaslight, a tallish man, walking with a slight stagger, and +carrying a white goose slung over his shoulder. As he reached the +corner of Goodge Street, a row broke out between this stranger +and a little knot of roughs. One of the latter knocked off the +man's hat, on which he raised his stick to defend himself and, +swinging it over his head, smashed the shop window behind him. +Peterson had rushed forward to protect the stranger from his +assailants; but the man, shocked at having broken the window, and +seeing an official-looking person in uniform rushing towards him, +dropped his goose, took to his heels, and vanished amid the +labyrinth of small streets which lie at the back of Tottenham +Court Road. The roughs had also fled at the appearance of +Peterson, so that he was left in possession of the field of +battle, and also of the spoils of victory in the shape of this +battered hat and a most unimpeachable Christmas goose." + +"Which surely he restored to their owner?" + +"My dear fellow, there lies the problem. It is true that 'For +Mrs. Henry Baker' was printed upon a small card which was tied to +the bird's left leg, and it is also true that the initials 'H. +B.' are legible upon the lining of this hat, but as there are +some thousands of Bakers, and some hundreds of Henry Bakers in +this city of ours, it is not easy to restore lost property to any +one of them." + +"What, then, did Peterson do?" + +"He brought round both hat and goose to me on Christmas morning, +knowing that even the smallest problems are of interest to me. +The goose we retained until this morning, when there were signs +that, in spite of the slight frost, it would be well that it +should be eaten without unnecessary delay. Its finder has carried +it off, therefore, to fulfil the ultimate destiny of a goose, +while I continue to retain the hat of the unknown gentleman who +lost his Christmas dinner." + +"Did he not advertise?" + +"No." + +"Then, what clue could you have as to his identity?" + +"Only as much as we can deduce." + +"From his hat?" + +"Precisely." + +"But you are joking. What can you gather from this old battered +felt?" + +"Here is my lens. You know my methods. What can you gather +yourself as to the individuality of the man who has worn this +article?" + +I took the tattered object in my hands and turned it over rather +ruefully. It was a very ordinary black hat of the usual round +shape, hard and much the worse for wear. The lining had been of +red silk, but was a good deal discoloured. There was no maker's +name; but, as Holmes had remarked, the initials "H. B." were +scrawled upon one side. It was pierced in the brim for a +hat-securer, but the elastic was missing. For the rest, it was +cracked, exceedingly dusty, and spotted in several places, +although there seemed to have been some attempt to hide the +discoloured patches by smearing them with ink. + +"I can see nothing," said I, handing it back to my friend. + +"On the contrary, Watson, you can see everything. You fail, +however, to reason from what you see. You are too timid in +drawing your inferences." + +"Then, pray tell me what it is that you can infer from this hat?" + +He picked it up and gazed at it in the peculiar introspective +fashion which was characteristic of him. "It is perhaps less +suggestive than it might have been," he remarked, "and yet there +are a few inferences which are very distinct, and a few others +which represent at least a strong balance of probability. That +the man was highly intellectual is of course obvious upon the +face of it, and also that he was fairly well-to-do within the +last three years, although he has now fallen upon evil days. He +had foresight, but has less now than formerly, pointing to a +moral retrogression, which, when taken with the decline of his +fortunes, seems to indicate some evil influence, probably drink, +at work upon him. This may account also for the obvious fact that +his wife has ceased to love him." + +"My dear Holmes!" + +"He has, however, retained some degree of self-respect," he +continued, disregarding my remonstrance. "He is a man who leads a +sedentary life, goes out little, is out of training entirely, is +middle-aged, has grizzled hair which he has had cut within the +last few days, and which he anoints with lime-cream. These are +the more patent facts which are to be deduced from his hat. Also, +by the way, that it is extremely improbable that he has gas laid +on in his house." + +"You are certainly joking, Holmes." + +"Not in the least. Is it possible that even now, when I give you +these results, you are unable to see how they are attained?" + +"I have no doubt that I am very stupid, but I must confess that I +am unable to follow you. For example, how did you deduce that +this man was intellectual?" + +For answer Holmes clapped the hat upon his head. It came right +over the forehead and settled upon the bridge of his nose. "It is +a question of cubic capacity," said he; "a man with so large a +brain must have something in it." + +"The decline of his fortunes, then?" + +"This hat is three years old. These flat brims curled at the edge +came in then. It is a hat of the very best quality. Look at the +band of ribbed silk and the excellent lining. If this man could +afford to buy so expensive a hat three years ago, and has had no +hat since, then he has assuredly gone down in the world." + +"Well, that is clear enough, certainly. But how about the +foresight and the moral retrogression?" + +Sherlock Holmes laughed. "Here is the foresight," said he putting +his finger upon the little disc and loop of the hat-securer. +"They are never sold upon hats. If this man ordered one, it is a +sign of a certain amount of foresight, since he went out of his +way to take this precaution against the wind. But since we see +that he has broken the elastic and has not troubled to replace +it, it is obvious that he has less foresight now than formerly, +which is a distinct proof of a weakening nature. On the other +hand, he has endeavoured to conceal some of these stains upon the +felt by daubing them with ink, which is a sign that he has not +entirely lost his self-respect." + +"Your reasoning is certainly plausible." + +"The further points, that he is middle-aged, that his hair is +grizzled, that it has been recently cut, and that he uses +lime-cream, are all to be gathered from a close examination of the +lower part of the lining. The lens discloses a large number of +hair-ends, clean cut by the scissors of the barber. They all +appear to be adhesive, and there is a distinct odour of +lime-cream. This dust, you will observe, is not the gritty, grey +dust of the street but the fluffy brown dust of the house, +showing that it has been hung up indoors most of the time, while +the marks of moisture upon the inside are proof positive that the +wearer perspired very freely, and could therefore, hardly be in +the best of training." + +"But his wife--you said that she had ceased to love him." + +"This hat has not been brushed for weeks. When I see you, my dear +Watson, with a week's accumulation of dust upon your hat, and +when your wife allows you to go out in such a state, I shall fear +that you also have been unfortunate enough to lose your wife's +affection." + +"But he might be a bachelor." + +"Nay, he was bringing home the goose as a peace-offering to his +wife. Remember the card upon the bird's leg." + +"You have an answer to everything. But how on earth do you deduce +that the gas is not laid on in his house?" + +"One tallow stain, or even two, might come by chance; but when I +see no less than five, I think that there can be little doubt +that the individual must be brought into frequent contact with +burning tallow--walks upstairs at night probably with his hat in +one hand and a guttering candle in the other. Anyhow, he never +got tallow-stains from a gas-jet. Are you satisfied?" + +"Well, it is very ingenious," said I, laughing; "but since, as +you said just now, there has been no crime committed, and no harm +done save the loss of a goose, all this seems to be rather a +waste of energy." + +Sherlock Holmes had opened his mouth to reply, when the door flew +open, and Peterson, the commissionaire, rushed into the apartment +with flushed cheeks and the face of a man who is dazed with +astonishment. + +"The goose, Mr. Holmes! The goose, sir!" he gasped. + +"Eh? What of it, then? Has it returned to life and flapped off +through the kitchen window?" Holmes twisted himself round upon +the sofa to get a fairer view of the man's excited face. + +"See here, sir! See what my wife found in its crop!" He held out +his hand and displayed upon the centre of the palm a brilliantly +scintillating blue stone, rather smaller than a bean in size, but +of such purity and radiance that it twinkled like an electric +point in the dark hollow of his hand. + +Sherlock Holmes sat up with a whistle. "By Jove, Peterson!" said +he, "this is treasure trove indeed. I suppose you know what you +have got?" + +"A diamond, sir? A precious stone. It cuts into glass as though +it were putty." + +"It's more than a precious stone. It is the precious stone." + +"Not the Countess of Morcar's blue carbuncle!" I ejaculated. + +"Precisely so. I ought to know its size and shape, seeing that I +have read the advertisement about it in The Times every day +lately. It is absolutely unique, and its value can only be +conjectured, but the reward offered of 1000 pounds is certainly +not within a twentieth part of the market price." + +"A thousand pounds! Great Lord of mercy!" The commissionaire +plumped down into a chair and stared from one to the other of us. + +"That is the reward, and I have reason to know that there are +sentimental considerations in the background which would induce +the Countess to part with half her fortune if she could but +recover the gem." + +"It was lost, if I remember aright, at the Hotel Cosmopolitan," I +remarked. + +"Precisely so, on December 22nd, just five days ago. John Horner, +a plumber, was accused of having abstracted it from the lady's +jewel-case. The evidence against him was so strong that the case +has been referred to the Assizes. I have some account of the +matter here, I believe." He rummaged amid his newspapers, +glancing over the dates, until at last he smoothed one out, +doubled it over, and read the following paragraph: + +"Hotel Cosmopolitan Jewel Robbery. John Horner, 26, plumber, was +brought up upon the charge of having upon the 22nd inst., +abstracted from the jewel-case of the Countess of Morcar the +valuable gem known as the blue carbuncle. James Ryder, +upper-attendant at the hotel, gave his evidence to the effect +that he had shown Horner up to the dressing-room of the Countess +of Morcar upon the day of the robbery in order that he might +solder the second bar of the grate, which was loose. He had +remained with Horner some little time, but had finally been +called away. On returning, he found that Horner had disappeared, +that the bureau had been forced open, and that the small morocco +casket in which, as it afterwards transpired, the Countess was +accustomed to keep her jewel, was lying empty upon the +dressing-table. Ryder instantly gave the alarm, and Horner was +arrested the same evening; but the stone could not be found +either upon his person or in his rooms. Catherine Cusack, maid to +the Countess, deposed to having heard Ryder's cry of dismay on +discovering the robbery, and to having rushed into the room, +where she found matters as described by the last witness. +Inspector Bradstreet, B division, gave evidence as to the arrest +of Horner, who struggled frantically, and protested his innocence +in the strongest terms. Evidence of a previous conviction for +robbery having been given against the prisoner, the magistrate +refused to deal summarily with the offence, but referred it to +the Assizes. Horner, who had shown signs of intense emotion +during the proceedings, fainted away at the conclusion and was +carried out of court." + +"Hum! So much for the police-court," said Holmes thoughtfully, +tossing aside the paper. "The question for us now to solve is the +sequence of events leading from a rifled jewel-case at one end to +the crop of a goose in Tottenham Court Road at the other. You +see, Watson, our little deductions have suddenly assumed a much +more important and less innocent aspect. Here is the stone; the +stone came from the goose, and the goose came from Mr. Henry +Baker, the gentleman with the bad hat and all the other +characteristics with which I have bored you. So now we must set +ourselves very seriously to finding this gentleman and +ascertaining what part he has played in this little mystery. To +do this, we must try the simplest means first, and these lie +undoubtedly in an advertisement in all the evening papers. If +this fail, I shall have recourse to other methods." + +"What will you say?" + +"Give me a pencil and that slip of paper. Now, then: 'Found at +the corner of Goodge Street, a goose and a black felt hat. Mr. +Henry Baker can have the same by applying at 6:30 this evening at +221B, Baker Street.' That is clear and concise." + +"Very. But will he see it?" + +"Well, he is sure to keep an eye on the papers, since, to a poor +man, the loss was a heavy one. He was clearly so scared by his +mischance in breaking the window and by the approach of Peterson +that he thought of nothing but flight, but since then he must +have bitterly regretted the impulse which caused him to drop his +bird. Then, again, the introduction of his name will cause him to +see it, for everyone who knows him will direct his attention to +it. Here you are, Peterson, run down to the advertising agency +and have this put in the evening papers." + +"In which, sir?" + +"Oh, in the Globe, Star, Pall Mall, St. James's, Evening News, +Standard, Echo, and any others that occur to you." + +"Very well, sir. And this stone?" + +"Ah, yes, I shall keep the stone. Thank you. And, I say, +Peterson, just buy a goose on your way back and leave it here +with me, for we must have one to give to this gentleman in place +of the one which your family is now devouring." + +When the commissionaire had gone, Holmes took up the stone and +held it against the light. "It's a bonny thing," said he. "Just +see how it glints and sparkles. Of course it is a nucleus and +focus of crime. Every good stone is. They are the devil's pet +baits. In the larger and older jewels every facet may stand for a +bloody deed. This stone is not yet twenty years old. It was found +in the banks of the Amoy River in southern China and is remarkable +in having every characteristic of the carbuncle, save that it is +blue in shade instead of ruby red. In spite of its youth, it has +already a sinister history. There have been two murders, a +vitriol-throwing, a suicide, and several robberies brought about +for the sake of this forty-grain weight of crystallised charcoal. +Who would think that so pretty a toy would be a purveyor to the +gallows and the prison? I'll lock it up in my strong box now and +drop a line to the Countess to say that we have it." + +"Do you think that this man Horner is innocent?" + +"I cannot tell." + +"Well, then, do you imagine that this other one, Henry Baker, had +anything to do with the matter?" + +"It is, I think, much more likely that Henry Baker is an +absolutely innocent man, who had no idea that the bird which he +was carrying was of considerably more value than if it were made +of solid gold. That, however, I shall determine by a very simple +test if we have an answer to our advertisement." + +"And you can do nothing until then?" + +"Nothing." + +"In that case I shall continue my professional round. But I shall +come back in the evening at the hour you have mentioned, for I +should like to see the solution of so tangled a business." + +"Very glad to see you. I dine at seven. There is a woodcock, I +believe. By the way, in view of recent occurrences, perhaps I +ought to ask Mrs. Hudson to examine its crop." + +I had been delayed at a case, and it was a little after half-past +six when I found myself in Baker Street once more. As I +approached the house I saw a tall man in a Scotch bonnet with a +coat which was buttoned up to his chin waiting outside in the +bright semicircle which was thrown from the fanlight. Just as I +arrived the door was opened, and we were shown up together to +Holmes' room. + +"Mr. Henry Baker, I believe," said he, rising from his armchair +and greeting his visitor with the easy air of geniality which he +could so readily assume. "Pray take this chair by the fire, Mr. +Baker. It is a cold night, and I observe that your circulation is +more adapted for summer than for winter. Ah, Watson, you have +just come at the right time. Is that your hat, Mr. Baker?" + +"Yes, sir, that is undoubtedly my hat." + +He was a large man with rounded shoulders, a massive head, and a +broad, intelligent face, sloping down to a pointed beard of +grizzled brown. A touch of red in nose and cheeks, with a slight +tremor of his extended hand, recalled Holmes' surmise as to his +habits. His rusty black frock-coat was buttoned right up in +front, with the collar turned up, and his lank wrists protruded +from his sleeves without a sign of cuff or shirt. He spoke in a +slow staccato fashion, choosing his words with care, and gave the +impression generally of a man of learning and letters who had had +ill-usage at the hands of fortune. + +"We have retained these things for some days," said Holmes, +"because we expected to see an advertisement from you giving your +address. I am at a loss to know now why you did not advertise." + +Our visitor gave a rather shamefaced laugh. "Shillings have not +been so plentiful with me as they once were," he remarked. "I had +no doubt that the gang of roughs who assaulted me had carried off +both my hat and the bird. I did not care to spend more money in a +hopeless attempt at recovering them." + +"Very naturally. By the way, about the bird, we were compelled to +eat it." + +"To eat it!" Our visitor half rose from his chair in his +excitement. + +"Yes, it would have been of no use to anyone had we not done so. +But I presume that this other goose upon the sideboard, which is +about the same weight and perfectly fresh, will answer your +purpose equally well?" + +"Oh, certainly, certainly," answered Mr. Baker with a sigh of +relief. + +"Of course, we still have the feathers, legs, crop, and so on of +your own bird, so if you wish--" + +The man burst into a hearty laugh. "They might be useful to me as +relics of my adventure," said he, "but beyond that I can hardly +see what use the disjecta membra of my late acquaintance are +going to be to me. No, sir, I think that, with your permission, I +will confine my attentions to the excellent bird which I perceive +upon the sideboard." + +Sherlock Holmes glanced sharply across at me with a slight shrug +of his shoulders. + +"There is your hat, then, and there your bird," said he. "By the +way, would it bore you to tell me where you got the other one +from? I am somewhat of a fowl fancier, and I have seldom seen a +better grown goose." + +"Certainly, sir," said Baker, who had risen and tucked his newly +gained property under his arm. "There are a few of us who +frequent the Alpha Inn, near the Museum--we are to be found in +the Museum itself during the day, you understand. This year our +good host, Windigate by name, instituted a goose club, by which, +on consideration of some few pence every week, we were each to +receive a bird at Christmas. My pence were duly paid, and the +rest is familiar to you. I am much indebted to you, sir, for a +Scotch bonnet is fitted neither to my years nor my gravity." With +a comical pomposity of manner he bowed solemnly to both of us and +strode off upon his way. + +"So much for Mr. Henry Baker," said Holmes when he had closed the +door behind him. "It is quite certain that he knows nothing +whatever about the matter. Are you hungry, Watson?" + +"Not particularly." + +"Then I suggest that we turn our dinner into a supper and follow +up this clue while it is still hot." + +"By all means." + +It was a bitter night, so we drew on our ulsters and wrapped +cravats about our throats. Outside, the stars were shining coldly +in a cloudless sky, and the breath of the passers-by blew out +into smoke like so many pistol shots. Our footfalls rang out +crisply and loudly as we swung through the doctors' quarter, +Wimpole Street, Harley Street, and so through Wigmore Street into +Oxford Street. In a quarter of an hour we were in Bloomsbury at +the Alpha Inn, which is a small public-house at the corner of one +of the streets which runs down into Holborn. Holmes pushed open +the door of the private bar and ordered two glasses of beer from +the ruddy-faced, white-aproned landlord. + +"Your beer should be excellent if it is as good as your geese," +said he. + +"My geese!" The man seemed surprised. + +"Yes. I was speaking only half an hour ago to Mr. Henry Baker, +who was a member of your goose club." + +"Ah! yes, I see. But you see, sir, them's not our geese." + +"Indeed! Whose, then?" + +"Well, I got the two dozen from a salesman in Covent Garden." + +"Indeed? I know some of them. Which was it?" + +"Breckinridge is his name." + +"Ah! I don't know him. Well, here's your good health landlord, +and prosperity to your house. Good-night." + +"Now for Mr. Breckinridge," he continued, buttoning up his coat +as we came out into the frosty air. "Remember, Watson that though +we have so homely a thing as a goose at one end of this chain, we +have at the other a man who will certainly get seven years' penal +servitude unless we can establish his innocence. It is possible +that our inquiry may but confirm his guilt; but, in any case, we +have a line of investigation which has been missed by the police, +and which a singular chance has placed in our hands. Let us +follow it out to the bitter end. Faces to the south, then, and +quick march!" + +We passed across Holborn, down Endell Street, and so through a +zigzag of slums to Covent Garden Market. One of the largest +stalls bore the name of Breckinridge upon it, and the proprietor +a horsey-looking man, with a sharp face and trim side-whiskers was +helping a boy to put up the shutters. + +"Good-evening. It's a cold night," said Holmes. + +The salesman nodded and shot a questioning glance at my +companion. + +"Sold out of geese, I see," continued Holmes, pointing at the +bare slabs of marble. + +"Let you have five hundred to-morrow morning." + +"That's no good." + +"Well, there are some on the stall with the gas-flare." + +"Ah, but I was recommended to you." + +"Who by?" + +"The landlord of the Alpha." + +"Oh, yes; I sent him a couple of dozen." + +"Fine birds they were, too. Now where did you get them from?" + +To my surprise the question provoked a burst of anger from the +salesman. + +"Now, then, mister," said he, with his head cocked and his arms +akimbo, "what are you driving at? Let's have it straight, now." + +"It is straight enough. I should like to know who sold you the +geese which you supplied to the Alpha." + +"Well then, I shan't tell you. So now!" + +"Oh, it is a matter of no importance; but I don't know why you +should be so warm over such a trifle." + +"Warm! You'd be as warm, maybe, if you were as pestered as I am. +When I pay good money for a good article there should be an end +of the business; but it's 'Where are the geese?' and 'Who did you +sell the geese to?' and 'What will you take for the geese?' One +would think they were the only geese in the world, to hear the +fuss that is made over them." + +"Well, I have no connection with any other people who have been +making inquiries," said Holmes carelessly. "If you won't tell us +the bet is off, that is all. But I'm always ready to back my +opinion on a matter of fowls, and I have a fiver on it that the +bird I ate is country bred." + +"Well, then, you've lost your fiver, for it's town bred," snapped +the salesman. + +"It's nothing of the kind." + +"I say it is." + +"I don't believe it." + +"D'you think you know more about fowls than I, who have handled +them ever since I was a nipper? I tell you, all those birds that +went to the Alpha were town bred." + +"You'll never persuade me to believe that." + +"Will you bet, then?" + +"It's merely taking your money, for I know that I am right. But +I'll have a sovereign on with you, just to teach you not to be +obstinate." + +The salesman chuckled grimly. "Bring me the books, Bill," said +he. + +The small boy brought round a small thin volume and a great +greasy-backed one, laying them out together beneath the hanging +lamp. + +"Now then, Mr. Cocksure," said the salesman, "I thought that I +was out of geese, but before I finish you'll find that there is +still one left in my shop. You see this little book?" + +"Well?" + +"That's the list of the folk from whom I buy. D'you see? Well, +then, here on this page are the country folk, and the numbers +after their names are where their accounts are in the big ledger. +Now, then! You see this other page in red ink? Well, that is a +list of my town suppliers. Now, look at that third name. Just +read it out to me." + +"Mrs. Oakshott, 117, Brixton Road--249," read Holmes. + +"Quite so. Now turn that up in the ledger." + +Holmes turned to the page indicated. "Here you are, 'Mrs. +Oakshott, 117, Brixton Road, egg and poultry supplier.'" + +"Now, then, what's the last entry?" + +"'December 22nd. Twenty-four geese at 7s. 6d.'" + +"Quite so. There you are. And underneath?" + +"'Sold to Mr. Windigate of the Alpha, at 12s.'" + +"What have you to say now?" + +Sherlock Holmes looked deeply chagrined. He drew a sovereign from +his pocket and threw it down upon the slab, turning away with the +air of a man whose disgust is too deep for words. A few yards off +he stopped under a lamp-post and laughed in the hearty, noiseless +fashion which was peculiar to him. + +"When you see a man with whiskers of that cut and the 'Pink 'un' +protruding out of his pocket, you can always draw him by a bet," +said he. "I daresay that if I had put 100 pounds down in front of +him, that man would not have given me such complete information +as was drawn from him by the idea that he was doing me on a +wager. Well, Watson, we are, I fancy, nearing the end of our +quest, and the only point which remains to be determined is +whether we should go on to this Mrs. Oakshott to-night, or +whether we should reserve it for to-morrow. It is clear from what +that surly fellow said that there are others besides ourselves +who are anxious about the matter, and I should--" + +His remarks were suddenly cut short by a loud hubbub which broke +out from the stall which we had just left. Turning round we saw a +little rat-faced fellow standing in the centre of the circle of +yellow light which was thrown by the swinging lamp, while +Breckinridge, the salesman, framed in the door of his stall, was +shaking his fists fiercely at the cringing figure. + +"I've had enough of you and your geese," he shouted. "I wish you +were all at the devil together. If you come pestering me any more +with your silly talk I'll set the dog at you. You bring Mrs. +Oakshott here and I'll answer her, but what have you to do with +it? Did I buy the geese off you?" + +"No; but one of them was mine all the same," whined the little +man. + +"Well, then, ask Mrs. Oakshott for it." + +"She told me to ask you." + +"Well, you can ask the King of Proosia, for all I care. I've had +enough of it. Get out of this!" He rushed fiercely forward, and +the inquirer flitted away into the darkness. + +"Ha! this may save us a visit to Brixton Road," whispered Holmes. +"Come with me, and we will see what is to be made of this +fellow." Striding through the scattered knots of people who +lounged round the flaring stalls, my companion speedily overtook +the little man and touched him upon the shoulder. He sprang +round, and I could see in the gas-light that every vestige of +colour had been driven from his face. + +"Who are you, then? What do you want?" he asked in a quavering +voice. + +"You will excuse me," said Holmes blandly, "but I could not help +overhearing the questions which you put to the salesman just now. +I think that I could be of assistance to you." + +"You? Who are you? How could you know anything of the matter?" + +"My name is Sherlock Holmes. It is my business to know what other +people don't know." + +"But you can know nothing of this?" + +"Excuse me, I know everything of it. You are endeavouring to +trace some geese which were sold by Mrs. Oakshott, of Brixton +Road, to a salesman named Breckinridge, by him in turn to Mr. +Windigate, of the Alpha, and by him to his club, of which Mr. +Henry Baker is a member." + +"Oh, sir, you are the very man whom I have longed to meet," cried +the little fellow with outstretched hands and quivering fingers. +"I can hardly explain to you how interested I am in this matter." + +Sherlock Holmes hailed a four-wheeler which was passing. "In that +case we had better discuss it in a cosy room rather than in this +wind-swept market-place," said he. "But pray tell me, before we +go farther, who it is that I have the pleasure of assisting." + +The man hesitated for an instant. "My name is John Robinson," he +answered with a sidelong glance. + +"No, no; the real name," said Holmes sweetly. "It is always +awkward doing business with an alias." + +A flush sprang to the white cheeks of the stranger. "Well then," +said he, "my real name is James Ryder." + +"Precisely so. Head attendant at the Hotel Cosmopolitan. Pray +step into the cab, and I shall soon be able to tell you +everything which you would wish to know." + +The little man stood glancing from one to the other of us with +half-frightened, half-hopeful eyes, as one who is not sure +whether he is on the verge of a windfall or of a catastrophe. +Then he stepped into the cab, and in half an hour we were back in +the sitting-room at Baker Street. Nothing had been said during +our drive, but the high, thin breathing of our new companion, and +the claspings and unclaspings of his hands, spoke of the nervous +tension within him. + +"Here we are!" said Holmes cheerily as we filed into the room. +"The fire looks very seasonable in this weather. You look cold, +Mr. Ryder. Pray take the basket-chair. I will just put on my +slippers before we settle this little matter of yours. Now, then! +You want to know what became of those geese?" + +"Yes, sir." + +"Or rather, I fancy, of that goose. It was one bird, I imagine in +which you were interested--white, with a black bar across the +tail." + +Ryder quivered with emotion. "Oh, sir," he cried, "can you tell +me where it went to?" + +"It came here." + +"Here?" + +"Yes, and a most remarkable bird it proved. I don't wonder that +you should take an interest in it. It laid an egg after it was +dead--the bonniest, brightest little blue egg that ever was seen. +I have it here in my museum." + +Our visitor staggered to his feet and clutched the mantelpiece +with his right hand. Holmes unlocked his strong-box and held up +the blue carbuncle, which shone out like a star, with a cold, +brilliant, many-pointed radiance. Ryder stood glaring with a +drawn face, uncertain whether to claim or to disown it. + +"The game's up, Ryder," said Holmes quietly. "Hold up, man, or +you'll be into the fire! Give him an arm back into his chair, +Watson. He's not got blood enough to go in for felony with +impunity. Give him a dash of brandy. So! Now he looks a little +more human. What a shrimp it is, to be sure!" + +For a moment he had staggered and nearly fallen, but the brandy +brought a tinge of colour into his cheeks, and he sat staring +with frightened eyes at his accuser. + +"I have almost every link in my hands, and all the proofs which I +could possibly need, so there is little which you need tell me. +Still, that little may as well be cleared up to make the case +complete. You had heard, Ryder, of this blue stone of the +Countess of Morcar's?" + +"It was Catherine Cusack who told me of it," said he in a +crackling voice. + +"I see--her ladyship's waiting-maid. Well, the temptation of +sudden wealth so easily acquired was too much for you, as it has +been for better men before you; but you were not very scrupulous +in the means you used. It seems to me, Ryder, that there is the +making of a very pretty villain in you. You knew that this man +Horner, the plumber, had been concerned in some such matter +before, and that suspicion would rest the more readily upon him. +What did you do, then? You made some small job in my lady's +room--you and your confederate Cusack--and you managed that he +should be the man sent for. Then, when he had left, you rifled +the jewel-case, raised the alarm, and had this unfortunate man +arrested. You then--" + +Ryder threw himself down suddenly upon the rug and clutched at my +companion's knees. "For God's sake, have mercy!" he shrieked. +"Think of my father! Of my mother! It would break their hearts. I +never went wrong before! I never will again. I swear it. I'll +swear it on a Bible. Oh, don't bring it into court! For Christ's +sake, don't!" + +"Get back into your chair!" said Holmes sternly. "It is very well +to cringe and crawl now, but you thought little enough of this +poor Horner in the dock for a crime of which he knew nothing." + +"I will fly, Mr. Holmes. I will leave the country, sir. Then the +charge against him will break down." + +"Hum! We will talk about that. And now let us hear a true account +of the next act. How came the stone into the goose, and how came +the goose into the open market? Tell us the truth, for there lies +your only hope of safety." + +Ryder passed his tongue over his parched lips. "I will tell you +it just as it happened, sir," said he. "When Horner had been +arrested, it seemed to me that it would be best for me to get +away with the stone at once, for I did not know at what moment +the police might not take it into their heads to search me and my +room. There was no place about the hotel where it would be safe. +I went out, as if on some commission, and I made for my sister's +house. She had married a man named Oakshott, and lived in Brixton +Road, where she fattened fowls for the market. All the way there +every man I met seemed to me to be a policeman or a detective; +and, for all that it was a cold night, the sweat was pouring down +my face before I came to the Brixton Road. My sister asked me +what was the matter, and why I was so pale; but I told her that I +had been upset by the jewel robbery at the hotel. Then I went +into the back yard and smoked a pipe and wondered what it would +be best to do. + +"I had a friend once called Maudsley, who went to the bad, and +has just been serving his time in Pentonville. One day he had met +me, and fell into talk about the ways of thieves, and how they +could get rid of what they stole. I knew that he would be true to +me, for I knew one or two things about him; so I made up my mind +to go right on to Kilburn, where he lived, and take him into my +confidence. He would show me how to turn the stone into money. +But how to get to him in safety? I thought of the agonies I had +gone through in coming from the hotel. I might at any moment be +seized and searched, and there would be the stone in my waistcoat +pocket. I was leaning against the wall at the time and looking at +the geese which were waddling about round my feet, and suddenly +an idea came into my head which showed me how I could beat the +best detective that ever lived. + +"My sister had told me some weeks before that I might have the +pick of her geese for a Christmas present, and I knew that she +was always as good as her word. I would take my goose now, and in +it I would carry my stone to Kilburn. There was a little shed in +the yard, and behind this I drove one of the birds--a fine big +one, white, with a barred tail. I caught it, and prying its bill +open, I thrust the stone down its throat as far as my finger +could reach. The bird gave a gulp, and I felt the stone pass +along its gullet and down into its crop. But the creature flapped +and struggled, and out came my sister to know what was the +matter. As I turned to speak to her the brute broke loose and +fluttered off among the others. + +"'Whatever were you doing with that bird, Jem?' says she. + +"'Well,' said I, 'you said you'd give me one for Christmas, and I +was feeling which was the fattest.' + +"'Oh,' says she, 'we've set yours aside for you--Jem's bird, we +call it. It's the big white one over yonder. There's twenty-six +of them, which makes one for you, and one for us, and two dozen +for the market.' + +"'Thank you, Maggie,' says I; 'but if it is all the same to you, +I'd rather have that one I was handling just now.' + +"'The other is a good three pound heavier,' said she, 'and we +fattened it expressly for you.' + +"'Never mind. I'll have the other, and I'll take it now,' said I. + +"'Oh, just as you like,' said she, a little huffed. 'Which is it +you want, then?' + +"'That white one with the barred tail, right in the middle of the +flock.' + +"'Oh, very well. Kill it and take it with you.' + +"Well, I did what she said, Mr. Holmes, and I carried the bird +all the way to Kilburn. I told my pal what I had done, for he was +a man that it was easy to tell a thing like that to. He laughed +until he choked, and we got a knife and opened the goose. My +heart turned to water, for there was no sign of the stone, and I +knew that some terrible mistake had occurred. I left the bird, +rushed back to my sister's, and hurried into the back yard. There +was not a bird to be seen there. + +"'Where are they all, Maggie?' I cried. + +"'Gone to the dealer's, Jem.' + +"'Which dealer's?' + +"'Breckinridge, of Covent Garden.' + +"'But was there another with a barred tail?' I asked, 'the same +as the one I chose?' + +"'Yes, Jem; there were two barred-tailed ones, and I could never +tell them apart.' + +"Well, then, of course I saw it all, and I ran off as hard as my +feet would carry me to this man Breckinridge; but he had sold the +lot at once, and not one word would he tell me as to where they +had gone. You heard him yourselves to-night. Well, he has always +answered me like that. My sister thinks that I am going mad. +Sometimes I think that I am myself. And now--and now I am myself +a branded thief, without ever having touched the wealth for which +I sold my character. God help me! God help me!" He burst into +convulsive sobbing, with his face buried in his hands. + +There was a long silence, broken only by his heavy breathing and +by the measured tapping of Sherlock Holmes' finger-tips upon the +edge of the table. Then my friend rose and threw open the door. + +"Get out!" said he. + +"What, sir! Oh, Heaven bless you!" + +"No more words. Get out!" + +And no more words were needed. There was a rush, a clatter upon +the stairs, the bang of a door, and the crisp rattle of running +footfalls from the street. + +"After all, Watson," said Holmes, reaching up his hand for his +clay pipe, "I am not retained by the police to supply their +deficiencies. If Horner were in danger it would be another thing; +but this fellow will not appear against him, and the case must +collapse. I suppose that I am commuting a felony, but it is just +possible that I am saving a soul. This fellow will not go wrong +again; he is too terribly frightened. Send him to gaol now, and +you make him a gaol-bird for life. Besides, it is the season of +forgiveness. Chance has put in our way a most singular and +whimsical problem, and its solution is its own reward. If you +will have the goodness to touch the bell, Doctor, we will begin +another investigation, in which, also a bird will be the chief +feature." + + + +VIII. THE ADVENTURE OF THE SPECKLED BAND + +On glancing over my notes of the seventy odd cases in which I +have during the last eight years studied the methods of my friend +Sherlock Holmes, I find many tragic, some comic, a large number +merely strange, but none commonplace; for, working as he did +rather for the love of his art than for the acquirement of +wealth, he refused to associate himself with any investigation +which did not tend towards the unusual, and even the fantastic. +Of all these varied cases, however, I cannot recall any which +presented more singular features than that which was associated +with the well-known Surrey family of the Roylotts of Stoke Moran. +The events in question occurred in the early days of my +association with Holmes, when we were sharing rooms as bachelors +in Baker Street. It is possible that I might have placed them +upon record before, but a promise of secrecy was made at the +time, from which I have only been freed during the last month by +the untimely death of the lady to whom the pledge was given. It +is perhaps as well that the facts should now come to light, for I +have reasons to know that there are widespread rumours as to the +death of Dr. Grimesby Roylott which tend to make the matter even +more terrible than the truth. + +It was early in April in the year '83 that I woke one morning to +find Sherlock Holmes standing, fully dressed, by the side of my +bed. He was a late riser, as a rule, and as the clock on the +mantelpiece showed me that it was only a quarter-past seven, I +blinked up at him in some surprise, and perhaps just a little +resentment, for I was myself regular in my habits. + +"Very sorry to knock you up, Watson," said he, "but it's the +common lot this morning. Mrs. Hudson has been knocked up, she +retorted upon me, and I on you." + +"What is it, then--a fire?" + +"No; a client. It seems that a young lady has arrived in a +considerable state of excitement, who insists upon seeing me. She +is waiting now in the sitting-room. Now, when young ladies wander +about the metropolis at this hour of the morning, and knock +sleepy people up out of their beds, I presume that it is +something very pressing which they have to communicate. Should it +prove to be an interesting case, you would, I am sure, wish to +follow it from the outset. I thought, at any rate, that I should +call you and give you the chance." + +"My dear fellow, I would not miss it for anything." + +I had no keener pleasure than in following Holmes in his +professional investigations, and in admiring the rapid +deductions, as swift as intuitions, and yet always founded on a +logical basis with which he unravelled the problems which were +submitted to him. I rapidly threw on my clothes and was ready in +a few minutes to accompany my friend down to the sitting-room. A +lady dressed in black and heavily veiled, who had been sitting in +the window, rose as we entered. + +"Good-morning, madam," said Holmes cheerily. "My name is Sherlock +Holmes. This is my intimate friend and associate, Dr. Watson, +before whom you can speak as freely as before myself. Ha! I am +glad to see that Mrs. Hudson has had the good sense to light the +fire. Pray draw up to it, and I shall order you a cup of hot +coffee, for I observe that you are shivering." + +"It is not cold which makes me shiver," said the woman in a low +voice, changing her seat as requested. + +"What, then?" + +"It is fear, Mr. Holmes. It is terror." She raised her veil as +she spoke, and we could see that she was indeed in a pitiable +state of agitation, her face all drawn and grey, with restless +frightened eyes, like those of some hunted animal. Her features +and figure were those of a woman of thirty, but her hair was shot +with premature grey, and her expression was weary and haggard. +Sherlock Holmes ran her over with one of his quick, +all-comprehensive glances. + +"You must not fear," said he soothingly, bending forward and +patting her forearm. "We shall soon set matters right, I have no +doubt. You have come in by train this morning, I see." + +"You know me, then?" + +"No, but I observe the second half of a return ticket in the palm +of your left glove. You must have started early, and yet you had +a good drive in a dog-cart, along heavy roads, before you reached +the station." + +The lady gave a violent start and stared in bewilderment at my +companion. + +"There is no mystery, my dear madam," said he, smiling. "The left +arm of your jacket is spattered with mud in no less than seven +places. The marks are perfectly fresh. There is no vehicle save a +dog-cart which throws up mud in that way, and then only when you +sit on the left-hand side of the driver." + +"Whatever your reasons may be, you are perfectly correct," said +she. "I started from home before six, reached Leatherhead at +twenty past, and came in by the first train to Waterloo. Sir, I +can stand this strain no longer; I shall go mad if it continues. +I have no one to turn to--none, save only one, who cares for me, +and he, poor fellow, can be of little aid. I have heard of you, +Mr. Holmes; I have heard of you from Mrs. Farintosh, whom you +helped in the hour of her sore need. It was from her that I had +your address. Oh, sir, do you not think that you could help me, +too, and at least throw a little light through the dense darkness +which surrounds me? At present it is out of my power to reward +you for your services, but in a month or six weeks I shall be +married, with the control of my own income, and then at least you +shall not find me ungrateful." + +Holmes turned to his desk and, unlocking it, drew out a small +case-book, which he consulted. + +"Farintosh," said he. "Ah yes, I recall the case; it was +concerned with an opal tiara. I think it was before your time, +Watson. I can only say, madam, that I shall be happy to devote +the same care to your case as I did to that of your friend. As to +reward, my profession is its own reward; but you are at liberty +to defray whatever expenses I may be put to, at the time which +suits you best. And now I beg that you will lay before us +everything that may help us in forming an opinion upon the +matter." + +"Alas!" replied our visitor, "the very horror of my situation +lies in the fact that my fears are so vague, and my suspicions +depend so entirely upon small points, which might seem trivial to +another, that even he to whom of all others I have a right to +look for help and advice looks upon all that I tell him about it +as the fancies of a nervous woman. He does not say so, but I can +read it from his soothing answers and averted eyes. But I have +heard, Mr. Holmes, that you can see deeply into the manifold +wickedness of the human heart. You may advise me how to walk amid +the dangers which encompass me." + +"I am all attention, madam." + +"My name is Helen Stoner, and I am living with my stepfather, who +is the last survivor of one of the oldest Saxon families in +England, the Roylotts of Stoke Moran, on the western border of +Surrey." + +Holmes nodded his head. "The name is familiar to me," said he. + +"The family was at one time among the richest in England, and the +estates extended over the borders into Berkshire in the north, +and Hampshire in the west. In the last century, however, four +successive heirs were of a dissolute and wasteful disposition, +and the family ruin was eventually completed by a gambler in the +days of the Regency. Nothing was left save a few acres of ground, +and the two-hundred-year-old house, which is itself crushed under +a heavy mortgage. The last squire dragged out his existence +there, living the horrible life of an aristocratic pauper; but +his only son, my stepfather, seeing that he must adapt himself to +the new conditions, obtained an advance from a relative, which +enabled him to take a medical degree and went out to Calcutta, +where, by his professional skill and his force of character, he +established a large practice. In a fit of anger, however, caused +by some robberies which had been perpetrated in the house, he +beat his native butler to death and narrowly escaped a capital +sentence. As it was, he suffered a long term of imprisonment and +afterwards returned to England a morose and disappointed man. + +"When Dr. Roylott was in India he married my mother, Mrs. Stoner, +the young widow of Major-General Stoner, of the Bengal Artillery. +My sister Julia and I were twins, and we were only two years old +at the time of my mother's re-marriage. She had a considerable +sum of money--not less than 1000 pounds a year--and this she +bequeathed to Dr. Roylott entirely while we resided with him, +with a provision that a certain annual sum should be allowed to +each of us in the event of our marriage. Shortly after our return +to England my mother died--she was killed eight years ago in a +railway accident near Crewe. Dr. Roylott then abandoned his +attempts to establish himself in practice in London and took us +to live with him in the old ancestral house at Stoke Moran. The +money which my mother had left was enough for all our wants, and +there seemed to be no obstacle to our happiness. + +"But a terrible change came over our stepfather about this time. +Instead of making friends and exchanging visits with our +neighbours, who had at first been overjoyed to see a Roylott of +Stoke Moran back in the old family seat, he shut himself up in +his house and seldom came out save to indulge in ferocious +quarrels with whoever might cross his path. Violence of temper +approaching to mania has been hereditary in the men of the +family, and in my stepfather's case it had, I believe, been +intensified by his long residence in the tropics. A series of +disgraceful brawls took place, two of which ended in the +police-court, until at last he became the terror of the village, +and the folks would fly at his approach, for he is a man of +immense strength, and absolutely uncontrollable in his anger. + +"Last week he hurled the local blacksmith over a parapet into a +stream, and it was only by paying over all the money which I +could gather together that I was able to avert another public +exposure. He had no friends at all save the wandering gipsies, +and he would give these vagabonds leave to encamp upon the few +acres of bramble-covered land which represent the family estate, +and would accept in return the hospitality of their tents, +wandering away with them sometimes for weeks on end. He has a +passion also for Indian animals, which are sent over to him by a +correspondent, and he has at this moment a cheetah and a baboon, +which wander freely over his grounds and are feared by the +villagers almost as much as their master. + +"You can imagine from what I say that my poor sister Julia and I +had no great pleasure in our lives. No servant would stay with +us, and for a long time we did all the work of the house. She was +but thirty at the time of her death, and yet her hair had already +begun to whiten, even as mine has." + +"Your sister is dead, then?" + +"She died just two years ago, and it is of her death that I wish +to speak to you. You can understand that, living the life which I +have described, we were little likely to see anyone of our own +age and position. We had, however, an aunt, my mother's maiden +sister, Miss Honoria Westphail, who lives near Harrow, and we +were occasionally allowed to pay short visits at this lady's +house. Julia went there at Christmas two years ago, and met there +a half-pay major of marines, to whom she became engaged. My +stepfather learned of the engagement when my sister returned and +offered no objection to the marriage; but within a fortnight of +the day which had been fixed for the wedding, the terrible event +occurred which has deprived me of my only companion." + +Sherlock Holmes had been leaning back in his chair with his eyes +closed and his head sunk in a cushion, but he half opened his +lids now and glanced across at his visitor. + +"Pray be precise as to details," said he. + +"It is easy for me to be so, for every event of that dreadful +time is seared into my memory. The manor-house is, as I have +already said, very old, and only one wing is now inhabited. The +bedrooms in this wing are on the ground floor, the sitting-rooms +being in the central block of the buildings. Of these bedrooms +the first is Dr. Roylott's, the second my sister's, and the third +my own. There is no communication between them, but they all open +out into the same corridor. Do I make myself plain?" + +"Perfectly so." + +"The windows of the three rooms open out upon the lawn. That +fatal night Dr. Roylott had gone to his room early, though we +knew that he had not retired to rest, for my sister was troubled +by the smell of the strong Indian cigars which it was his custom +to smoke. She left her room, therefore, and came into mine, where +she sat for some time, chatting about her approaching wedding. At +eleven o'clock she rose to leave me, but she paused at the door +and looked back. + +"'Tell me, Helen,' said she, 'have you ever heard anyone whistle +in the dead of the night?' + +"'Never,' said I. + +"'I suppose that you could not possibly whistle, yourself, in +your sleep?' + +"'Certainly not. But why?' + +"'Because during the last few nights I have always, about three +in the morning, heard a low, clear whistle. I am a light sleeper, +and it has awakened me. I cannot tell where it came from--perhaps +from the next room, perhaps from the lawn. I thought that I would +just ask you whether you had heard it.' + +"'No, I have not. It must be those wretched gipsies in the +plantation.' + +"'Very likely. And yet if it were on the lawn, I wonder that you +did not hear it also.' + +"'Ah, but I sleep more heavily than you.' + +"'Well, it is of no great consequence, at any rate.' She smiled +back at me, closed my door, and a few moments later I heard her +key turn in the lock." + +"Indeed," said Holmes. "Was it your custom always to lock +yourselves in at night?" + +"Always." + +"And why?" + +"I think that I mentioned to you that the doctor kept a cheetah +and a baboon. We had no feeling of security unless our doors were +locked." + +"Quite so. Pray proceed with your statement." + +"I could not sleep that night. A vague feeling of impending +misfortune impressed me. My sister and I, you will recollect, +were twins, and you know how subtle are the links which bind two +souls which are so closely allied. It was a wild night. The wind +was howling outside, and the rain was beating and splashing +against the windows. Suddenly, amid all the hubbub of the gale, +there burst forth the wild scream of a terrified woman. I knew +that it was my sister's voice. I sprang from my bed, wrapped a +shawl round me, and rushed into the corridor. As I opened my door +I seemed to hear a low whistle, such as my sister described, and +a few moments later a clanging sound, as if a mass of metal had +fallen. As I ran down the passage, my sister's door was unlocked, +and revolved slowly upon its hinges. I stared at it +horror-stricken, not knowing what was about to issue from it. By +the light of the corridor-lamp I saw my sister appear at the +opening, her face blanched with terror, her hands groping for +help, her whole figure swaying to and fro like that of a +drunkard. I ran to her and threw my arms round her, but at that +moment her knees seemed to give way and she fell to the ground. +She writhed as one who is in terrible pain, and her limbs were +dreadfully convulsed. At first I thought that she had not +recognised me, but as I bent over her she suddenly shrieked out +in a voice which I shall never forget, 'Oh, my God! Helen! It was +the band! The speckled band!' There was something else which she +would fain have said, and she stabbed with her finger into the +air in the direction of the doctor's room, but a fresh convulsion +seized her and choked her words. I rushed out, calling loudly for +my stepfather, and I met him hastening from his room in his +dressing-gown. When he reached my sister's side she was +unconscious, and though he poured brandy down her throat and sent +for medical aid from the village, all efforts were in vain, for +she slowly sank and died without having recovered her +consciousness. Such was the dreadful end of my beloved sister." + +"One moment," said Holmes, "are you sure about this whistle and +metallic sound? Could you swear to it?" + +"That was what the county coroner asked me at the inquiry. It is +my strong impression that I heard it, and yet, among the crash of +the gale and the creaking of an old house, I may possibly have +been deceived." + +"Was your sister dressed?" + +"No, she was in her night-dress. In her right hand was found the +charred stump of a match, and in her left a match-box." + +"Showing that she had struck a light and looked about her when +the alarm took place. That is important. And what conclusions did +the coroner come to?" + +"He investigated the case with great care, for Dr. Roylott's +conduct had long been notorious in the county, but he was unable +to find any satisfactory cause of death. My evidence showed that +the door had been fastened upon the inner side, and the windows +were blocked by old-fashioned shutters with broad iron bars, +which were secured every night. The walls were carefully sounded, +and were shown to be quite solid all round, and the flooring was +also thoroughly examined, with the same result. The chimney is +wide, but is barred up by four large staples. It is certain, +therefore, that my sister was quite alone when she met her end. +Besides, there were no marks of any violence upon her." + +"How about poison?" + +"The doctors examined her for it, but without success." + +"What do you think that this unfortunate lady died of, then?" + +"It is my belief that she died of pure fear and nervous shock, +though what it was that frightened her I cannot imagine." + +"Were there gipsies in the plantation at the time?" + +"Yes, there are nearly always some there." + +"Ah, and what did you gather from this allusion to a band--a +speckled band?" + +"Sometimes I have thought that it was merely the wild talk of +delirium, sometimes that it may have referred to some band of +people, perhaps to these very gipsies in the plantation. I do not +know whether the spotted handkerchiefs which so many of them wear +over their heads might have suggested the strange adjective which +she used." + +Holmes shook his head like a man who is far from being satisfied. + +"These are very deep waters," said he; "pray go on with your +narrative." + +"Two years have passed since then, and my life has been until +lately lonelier than ever. A month ago, however, a dear friend, +whom I have known for many years, has done me the honour to ask +my hand in marriage. His name is Armitage--Percy Armitage--the +second son of Mr. Armitage, of Crane Water, near Reading. My +stepfather has offered no opposition to the match, and we are to +be married in the course of the spring. Two days ago some repairs +were started in the west wing of the building, and my bedroom +wall has been pierced, so that I have had to move into the +chamber in which my sister died, and to sleep in the very bed in +which she slept. Imagine, then, my thrill of terror when last +night, as I lay awake, thinking over her terrible fate, I +suddenly heard in the silence of the night the low whistle which +had been the herald of her own death. I sprang up and lit the +lamp, but nothing was to be seen in the room. I was too shaken to +go to bed again, however, so I dressed, and as soon as it was +daylight I slipped down, got a dog-cart at the Crown Inn, which +is opposite, and drove to Leatherhead, from whence I have come on +this morning with the one object of seeing you and asking your +advice." + +"You have done wisely," said my friend. "But have you told me +all?" + +"Yes, all." + +"Miss Roylott, you have not. You are screening your stepfather." + +"Why, what do you mean?" + +For answer Holmes pushed back the frill of black lace which +fringed the hand that lay upon our visitor's knee. Five little +livid spots, the marks of four fingers and a thumb, were printed +upon the white wrist. + +"You have been cruelly used," said Holmes. + +The lady coloured deeply and covered over her injured wrist. "He +is a hard man," she said, "and perhaps he hardly knows his own +strength." + +There was a long silence, during which Holmes leaned his chin +upon his hands and stared into the crackling fire. + +"This is a very deep business," he said at last. "There are a +thousand details which I should desire to know before I decide +upon our course of action. Yet we have not a moment to lose. If +we were to come to Stoke Moran to-day, would it be possible for +us to see over these rooms without the knowledge of your +stepfather?" + +"As it happens, he spoke of coming into town to-day upon some +most important business. It is probable that he will be away all +day, and that there would be nothing to disturb you. We have a +housekeeper now, but she is old and foolish, and I could easily +get her out of the way." + +"Excellent. You are not averse to this trip, Watson?" + +"By no means." + +"Then we shall both come. What are you going to do yourself?" + +"I have one or two things which I would wish to do now that I am +in town. But I shall return by the twelve o'clock train, so as to +be there in time for your coming." + +"And you may expect us early in the afternoon. I have myself some +small business matters to attend to. Will you not wait and +breakfast?" + +"No, I must go. My heart is lightened already since I have +confided my trouble to you. I shall look forward to seeing you +again this afternoon." She dropped her thick black veil over her +face and glided from the room. + +"And what do you think of it all, Watson?" asked Sherlock Holmes, +leaning back in his chair. + +"It seems to me to be a most dark and sinister business." + +"Dark enough and sinister enough." + +"Yet if the lady is correct in saying that the flooring and walls +are sound, and that the door, window, and chimney are impassable, +then her sister must have been undoubtedly alone when she met her +mysterious end." + +"What becomes, then, of these nocturnal whistles, and what of the +very peculiar words of the dying woman?" + +"I cannot think." + +"When you combine the ideas of whistles at night, the presence of +a band of gipsies who are on intimate terms with this old doctor, +the fact that we have every reason to believe that the doctor has +an interest in preventing his stepdaughter's marriage, the dying +allusion to a band, and, finally, the fact that Miss Helen Stoner +heard a metallic clang, which might have been caused by one of +those metal bars that secured the shutters falling back into its +place, I think that there is good ground to think that the +mystery may be cleared along those lines." + +"But what, then, did the gipsies do?" + +"I cannot imagine." + +"I see many objections to any such theory." + +"And so do I. It is precisely for that reason that we are going +to Stoke Moran this day. I want to see whether the objections are +fatal, or if they may be explained away. But what in the name of +the devil!" + +The ejaculation had been drawn from my companion by the fact that +our door had been suddenly dashed open, and that a huge man had +framed himself in the aperture. His costume was a peculiar +mixture of the professional and of the agricultural, having a +black top-hat, a long frock-coat, and a pair of high gaiters, +with a hunting-crop swinging in his hand. So tall was he that his +hat actually brushed the cross bar of the doorway, and his +breadth seemed to span it across from side to side. A large face, +seared with a thousand wrinkles, burned yellow with the sun, and +marked with every evil passion, was turned from one to the other +of us, while his deep-set, bile-shot eyes, and his high, thin, +fleshless nose, gave him somewhat the resemblance to a fierce old +bird of prey. + +"Which of you is Holmes?" asked this apparition. + +"My name, sir; but you have the advantage of me," said my +companion quietly. + +"I am Dr. Grimesby Roylott, of Stoke Moran." + +"Indeed, Doctor," said Holmes blandly. "Pray take a seat." + +"I will do nothing of the kind. My stepdaughter has been here. I +have traced her. What has she been saying to you?" + +"It is a little cold for the time of the year," said Holmes. + +"What has she been saying to you?" screamed the old man +furiously. + +"But I have heard that the crocuses promise well," continued my +companion imperturbably. + +"Ha! You put me off, do you?" said our new visitor, taking a step +forward and shaking his hunting-crop. "I know you, you scoundrel! +I have heard of you before. You are Holmes, the meddler." + +My friend smiled. + +"Holmes, the busybody!" + +His smile broadened. + +"Holmes, the Scotland Yard Jack-in-office!" + +Holmes chuckled heartily. "Your conversation is most +entertaining," said he. "When you go out close the door, for +there is a decided draught." + +"I will go when I have said my say. Don't you dare to meddle with +my affairs. I know that Miss Stoner has been here. I traced her! +I am a dangerous man to fall foul of! See here." He stepped +swiftly forward, seized the poker, and bent it into a curve with +his huge brown hands. + +"See that you keep yourself out of my grip," he snarled, and +hurling the twisted poker into the fireplace he strode out of the +room. + +"He seems a very amiable person," said Holmes, laughing. "I am +not quite so bulky, but if he had remained I might have shown him +that my grip was not much more feeble than his own." As he spoke +he picked up the steel poker and, with a sudden effort, +straightened it out again. + +"Fancy his having the insolence to confound me with the official +detective force! This incident gives zest to our investigation, +however, and I only trust that our little friend will not suffer +from her imprudence in allowing this brute to trace her. And now, +Watson, we shall order breakfast, and afterwards I shall walk +down to Doctors' Commons, where I hope to get some data which may +help us in this matter." + + +It was nearly one o'clock when Sherlock Holmes returned from his +excursion. He held in his hand a sheet of blue paper, scrawled +over with notes and figures. + +"I have seen the will of the deceased wife," said he. "To +determine its exact meaning I have been obliged to work out the +present prices of the investments with which it is concerned. The +total income, which at the time of the wife's death was little +short of 1100 pounds, is now, through the fall in agricultural +prices, not more than 750 pounds. Each daughter can claim an +income of 250 pounds, in case of marriage. It is evident, +therefore, that if both girls had married, this beauty would have +had a mere pittance, while even one of them would cripple him to +a very serious extent. My morning's work has not been wasted, +since it has proved that he has the very strongest motives for +standing in the way of anything of the sort. And now, Watson, +this is too serious for dawdling, especially as the old man is +aware that we are interesting ourselves in his affairs; so if you +are ready, we shall call a cab and drive to Waterloo. I should be +very much obliged if you would slip your revolver into your +pocket. An Eley's No. 2 is an excellent argument with gentlemen +who can twist steel pokers into knots. That and a tooth-brush +are, I think, all that we need." + +At Waterloo we were fortunate in catching a train for +Leatherhead, where we hired a trap at the station inn and drove +for four or five miles through the lovely Surrey lanes. It was a +perfect day, with a bright sun and a few fleecy clouds in the +heavens. The trees and wayside hedges were just throwing out +their first green shoots, and the air was full of the pleasant +smell of the moist earth. To me at least there was a strange +contrast between the sweet promise of the spring and this +sinister quest upon which we were engaged. My companion sat in +the front of the trap, his arms folded, his hat pulled down over +his eyes, and his chin sunk upon his breast, buried in the +deepest thought. Suddenly, however, he started, tapped me on the +shoulder, and pointed over the meadows. + +"Look there!" said he. + +A heavily timbered park stretched up in a gentle slope, +thickening into a grove at the highest point. From amid the +branches there jutted out the grey gables and high roof-tree of a +very old mansion. + +"Stoke Moran?" said he. + +"Yes, sir, that be the house of Dr. Grimesby Roylott," remarked +the driver. + +"There is some building going on there," said Holmes; "that is +where we are going." + +"There's the village," said the driver, pointing to a cluster of +roofs some distance to the left; "but if you want to get to the +house, you'll find it shorter to get over this stile, and so by +the foot-path over the fields. There it is, where the lady is +walking." + +"And the lady, I fancy, is Miss Stoner," observed Holmes, shading +his eyes. "Yes, I think we had better do as you suggest." + +We got off, paid our fare, and the trap rattled back on its way +to Leatherhead. + +"I thought it as well," said Holmes as we climbed the stile, +"that this fellow should think we had come here as architects, or +on some definite business. It may stop his gossip. +Good-afternoon, Miss Stoner. You see that we have been as good as +our word." + +Our client of the morning had hurried forward to meet us with a +face which spoke her joy. "I have been waiting so eagerly for +you," she cried, shaking hands with us warmly. "All has turned +out splendidly. Dr. Roylott has gone to town, and it is unlikely +that he will be back before evening." + +"We have had the pleasure of making the doctor's acquaintance," +said Holmes, and in a few words he sketched out what had +occurred. Miss Stoner turned white to the lips as she listened. + +"Good heavens!" she cried, "he has followed me, then." + +"So it appears." + +"He is so cunning that I never know when I am safe from him. What +will he say when he returns?" + +"He must guard himself, for he may find that there is someone +more cunning than himself upon his track. You must lock yourself +up from him to-night. If he is violent, we shall take you away to +your aunt's at Harrow. Now, we must make the best use of our +time, so kindly take us at once to the rooms which we are to +examine." + +The building was of grey, lichen-blotched stone, with a high +central portion and two curving wings, like the claws of a crab, +thrown out on each side. In one of these wings the windows were +broken and blocked with wooden boards, while the roof was partly +caved in, a picture of ruin. The central portion was in little +better repair, but the right-hand block was comparatively modern, +and the blinds in the windows, with the blue smoke curling up +from the chimneys, showed that this was where the family resided. +Some scaffolding had been erected against the end wall, and the +stone-work had been broken into, but there were no signs of any +workmen at the moment of our visit. Holmes walked slowly up and +down the ill-trimmed lawn and examined with deep attention the +outsides of the windows. + +"This, I take it, belongs to the room in which you used to sleep, +the centre one to your sister's, and the one next to the main +building to Dr. Roylott's chamber?" + +"Exactly so. But I am now sleeping in the middle one." + +"Pending the alterations, as I understand. By the way, there does +not seem to be any very pressing need for repairs at that end +wall." + +"There were none. I believe that it was an excuse to move me from +my room." + +"Ah! that is suggestive. Now, on the other side of this narrow +wing runs the corridor from which these three rooms open. There +are windows in it, of course?" + +"Yes, but very small ones. Too narrow for anyone to pass +through." + +"As you both locked your doors at night, your rooms were +unapproachable from that side. Now, would you have the kindness +to go into your room and bar your shutters?" + +Miss Stoner did so, and Holmes, after a careful examination +through the open window, endeavoured in every way to force the +shutter open, but without success. There was no slit through +which a knife could be passed to raise the bar. Then with his +lens he tested the hinges, but they were of solid iron, built +firmly into the massive masonry. "Hum!" said he, scratching his +chin in some perplexity, "my theory certainly presents some +difficulties. No one could pass these shutters if they were +bolted. Well, we shall see if the inside throws any light upon +the matter." + +A small side door led into the whitewashed corridor from which +the three bedrooms opened. Holmes refused to examine the third +chamber, so we passed at once to the second, that in which Miss +Stoner was now sleeping, and in which her sister had met with her +fate. It was a homely little room, with a low ceiling and a +gaping fireplace, after the fashion of old country-houses. A +brown chest of drawers stood in one corner, a narrow +white-counterpaned bed in another, and a dressing-table on the +left-hand side of the window. These articles, with two small +wicker-work chairs, made up all the furniture in the room save +for a square of Wilton carpet in the centre. The boards round and +the panelling of the walls were of brown, worm-eaten oak, so old +and discoloured that it may have dated from the original building +of the house. Holmes drew one of the chairs into a corner and sat +silent, while his eyes travelled round and round and up and down, +taking in every detail of the apartment. + +"Where does that bell communicate with?" he asked at last +pointing to a thick bell-rope which hung down beside the bed, the +tassel actually lying upon the pillow. + +"It goes to the housekeeper's room." + +"It looks newer than the other things?" + +"Yes, it was only put there a couple of years ago." + +"Your sister asked for it, I suppose?" + +"No, I never heard of her using it. We used always to get what we +wanted for ourselves." + +"Indeed, it seemed unnecessary to put so nice a bell-pull there. +You will excuse me for a few minutes while I satisfy myself as to +this floor." He threw himself down upon his face with his lens in +his hand and crawled swiftly backward and forward, examining +minutely the cracks between the boards. Then he did the same with +the wood-work with which the chamber was panelled. Finally he +walked over to the bed and spent some time in staring at it and +in running his eye up and down the wall. Finally he took the +bell-rope in his hand and gave it a brisk tug. + +"Why, it's a dummy," said he. + +"Won't it ring?" + +"No, it is not even attached to a wire. This is very interesting. +You can see now that it is fastened to a hook just above where +the little opening for the ventilator is." + +"How very absurd! I never noticed that before." + +"Very strange!" muttered Holmes, pulling at the rope. "There are +one or two very singular points about this room. For example, +what a fool a builder must be to open a ventilator into another +room, when, with the same trouble, he might have communicated +with the outside air!" + +"That is also quite modern," said the lady. + +"Done about the same time as the bell-rope?" remarked Holmes. + +"Yes, there were several little changes carried out about that +time." + +"They seem to have been of a most interesting character--dummy +bell-ropes, and ventilators which do not ventilate. With your +permission, Miss Stoner, we shall now carry our researches into +the inner apartment." + +Dr. Grimesby Roylott's chamber was larger than that of his +step-daughter, but was as plainly furnished. A camp-bed, a small +wooden shelf full of books, mostly of a technical character, an +armchair beside the bed, a plain wooden chair against the wall, a +round table, and a large iron safe were the principal things +which met the eye. Holmes walked slowly round and examined each +and all of them with the keenest interest. + +"What's in here?" he asked, tapping the safe. + +"My stepfather's business papers." + +"Oh! you have seen inside, then?" + +"Only once, some years ago. I remember that it was full of +papers." + +"There isn't a cat in it, for example?" + +"No. What a strange idea!" + +"Well, look at this!" He took up a small saucer of milk which +stood on the top of it. + +"No; we don't keep a cat. But there is a cheetah and a baboon." + +"Ah, yes, of course! Well, a cheetah is just a big cat, and yet a +saucer of milk does not go very far in satisfying its wants, I +daresay. There is one point which I should wish to determine." He +squatted down in front of the wooden chair and examined the seat +of it with the greatest attention. + +"Thank you. That is quite settled," said he, rising and putting +his lens in his pocket. "Hullo! Here is something interesting!" + +The object which had caught his eye was a small dog lash hung on +one corner of the bed. The lash, however, was curled upon itself +and tied so as to make a loop of whipcord. + +"What do you make of that, Watson?" + +"It's a common enough lash. But I don't know why it should be +tied." + +"That is not quite so common, is it? Ah, me! it's a wicked world, +and when a clever man turns his brains to crime it is the worst +of all. I think that I have seen enough now, Miss Stoner, and +with your permission we shall walk out upon the lawn." + +I had never seen my friend's face so grim or his brow so dark as +it was when we turned from the scene of this investigation. We +had walked several times up and down the lawn, neither Miss +Stoner nor myself liking to break in upon his thoughts before he +roused himself from his reverie. + +"It is very essential, Miss Stoner," said he, "that you should +absolutely follow my advice in every respect." + +"I shall most certainly do so." + +"The matter is too serious for any hesitation. Your life may +depend upon your compliance." + +"I assure you that I am in your hands." + +"In the first place, both my friend and I must spend the night in +your room." + +Both Miss Stoner and I gazed at him in astonishment. + +"Yes, it must be so. Let me explain. I believe that that is the +village inn over there?" + +"Yes, that is the Crown." + +"Very good. Your windows would be visible from there?" + +"Certainly." + +"You must confine yourself to your room, on pretence of a +headache, when your stepfather comes back. Then when you hear him +retire for the night, you must open the shutters of your window, +undo the hasp, put your lamp there as a signal to us, and then +withdraw quietly with everything which you are likely to want +into the room which you used to occupy. I have no doubt that, in +spite of the repairs, you could manage there for one night." + +"Oh, yes, easily." + +"The rest you will leave in our hands." + +"But what will you do?" + +"We shall spend the night in your room, and we shall investigate +the cause of this noise which has disturbed you." + +"I believe, Mr. Holmes, that you have already made up your mind," +said Miss Stoner, laying her hand upon my companion's sleeve. + +"Perhaps I have." + +"Then, for pity's sake, tell me what was the cause of my sister's +death." + +"I should prefer to have clearer proofs before I speak." + +"You can at least tell me whether my own thought is correct, and +if she died from some sudden fright." + +"No, I do not think so. I think that there was probably some more +tangible cause. And now, Miss Stoner, we must leave you for if +Dr. Roylott returned and saw us our journey would be in vain. +Good-bye, and be brave, for if you will do what I have told you, +you may rest assured that we shall soon drive away the dangers +that threaten you." + +Sherlock Holmes and I had no difficulty in engaging a bedroom and +sitting-room at the Crown Inn. They were on the upper floor, and +from our window we could command a view of the avenue gate, and +of the inhabited wing of Stoke Moran Manor House. At dusk we saw +Dr. Grimesby Roylott drive past, his huge form looming up beside +the little figure of the lad who drove him. The boy had some +slight difficulty in undoing the heavy iron gates, and we heard +the hoarse roar of the doctor's voice and saw the fury with which +he shook his clinched fists at him. The trap drove on, and a few +minutes later we saw a sudden light spring up among the trees as +the lamp was lit in one of the sitting-rooms. + +"Do you know, Watson," said Holmes as we sat together in the +gathering darkness, "I have really some scruples as to taking you +to-night. There is a distinct element of danger." + +"Can I be of assistance?" + +"Your presence might be invaluable." + +"Then I shall certainly come." + +"It is very kind of you." + +"You speak of danger. You have evidently seen more in these rooms +than was visible to me." + +"No, but I fancy that I may have deduced a little more. I imagine +that you saw all that I did." + +"I saw nothing remarkable save the bell-rope, and what purpose +that could answer I confess is more than I can imagine." + +"You saw the ventilator, too?" + +"Yes, but I do not think that it is such a very unusual thing to +have a small opening between two rooms. It was so small that a +rat could hardly pass through." + +"I knew that we should find a ventilator before ever we came to +Stoke Moran." + +"My dear Holmes!" + +"Oh, yes, I did. You remember in her statement she said that her +sister could smell Dr. Roylott's cigar. Now, of course that +suggested at once that there must be a communication between the +two rooms. It could only be a small one, or it would have been +remarked upon at the coroner's inquiry. I deduced a ventilator." + +"But what harm can there be in that?" + +"Well, there is at least a curious coincidence of dates. A +ventilator is made, a cord is hung, and a lady who sleeps in the +bed dies. Does not that strike you?" + +"I cannot as yet see any connection." + +"Did you observe anything very peculiar about that bed?" + +"No." + +"It was clamped to the floor. Did you ever see a bed fastened +like that before?" + +"I cannot say that I have." + +"The lady could not move her bed. It must always be in the same +relative position to the ventilator and to the rope--or so we may +call it, since it was clearly never meant for a bell-pull." + +"Holmes," I cried, "I seem to see dimly what you are hinting at. +We are only just in time to prevent some subtle and horrible +crime." + +"Subtle enough and horrible enough. When a doctor does go wrong +he is the first of criminals. He has nerve and he has knowledge. +Palmer and Pritchard were among the heads of their profession. +This man strikes even deeper, but I think, Watson, that we shall +be able to strike deeper still. But we shall have horrors enough +before the night is over; for goodness' sake let us have a quiet +pipe and turn our minds for a few hours to something more +cheerful." + + +About nine o'clock the light among the trees was extinguished, +and all was dark in the direction of the Manor House. Two hours +passed slowly away, and then, suddenly, just at the stroke of +eleven, a single bright light shone out right in front of us. + +"That is our signal," said Holmes, springing to his feet; "it +comes from the middle window." + +As we passed out he exchanged a few words with the landlord, +explaining that we were going on a late visit to an acquaintance, +and that it was possible that we might spend the night there. A +moment later we were out on the dark road, a chill wind blowing +in our faces, and one yellow light twinkling in front of us +through the gloom to guide us on our sombre errand. + +There was little difficulty in entering the grounds, for +unrepaired breaches gaped in the old park wall. Making our way +among the trees, we reached the lawn, crossed it, and were about +to enter through the window when out from a clump of laurel +bushes there darted what seemed to be a hideous and distorted +child, who threw itself upon the grass with writhing limbs and +then ran swiftly across the lawn into the darkness. + +"My God!" I whispered; "did you see it?" + +Holmes was for the moment as startled as I. His hand closed like +a vice upon my wrist in his agitation. Then he broke into a low +laugh and put his lips to my ear. + +"It is a nice household," he murmured. "That is the baboon." + +I had forgotten the strange pets which the doctor affected. There +was a cheetah, too; perhaps we might find it upon our shoulders +at any moment. I confess that I felt easier in my mind when, +after following Holmes' example and slipping off my shoes, I +found myself inside the bedroom. My companion noiselessly closed +the shutters, moved the lamp onto the table, and cast his eyes +round the room. All was as we had seen it in the daytime. Then +creeping up to me and making a trumpet of his hand, he whispered +into my ear again so gently that it was all that I could do to +distinguish the words: + +"The least sound would be fatal to our plans." + +I nodded to show that I had heard. + +"We must sit without light. He would see it through the +ventilator." + +I nodded again. + +"Do not go asleep; your very life may depend upon it. Have your +pistol ready in case we should need it. I will sit on the side of +the bed, and you in that chair." + +I took out my revolver and laid it on the corner of the table. + +Holmes had brought up a long thin cane, and this he placed upon +the bed beside him. By it he laid the box of matches and the +stump of a candle. Then he turned down the lamp, and we were left +in darkness. + +How shall I ever forget that dreadful vigil? I could not hear a +sound, not even the drawing of a breath, and yet I knew that my +companion sat open-eyed, within a few feet of me, in the same +state of nervous tension in which I was myself. The shutters cut +off the least ray of light, and we waited in absolute darkness. + +From outside came the occasional cry of a night-bird, and once at +our very window a long drawn catlike whine, which told us that +the cheetah was indeed at liberty. Far away we could hear the +deep tones of the parish clock, which boomed out every quarter of +an hour. How long they seemed, those quarters! Twelve struck, and +one and two and three, and still we sat waiting silently for +whatever might befall. + +Suddenly there was the momentary gleam of a light up in the +direction of the ventilator, which vanished immediately, but was +succeeded by a strong smell of burning oil and heated metal. +Someone in the next room had lit a dark-lantern. I heard a gentle +sound of movement, and then all was silent once more, though the +smell grew stronger. For half an hour I sat with straining ears. +Then suddenly another sound became audible--a very gentle, +soothing sound, like that of a small jet of steam escaping +continually from a kettle. The instant that we heard it, Holmes +sprang from the bed, struck a match, and lashed furiously with +his cane at the bell-pull. + +"You see it, Watson?" he yelled. "You see it?" + +But I saw nothing. At the moment when Holmes struck the light I +heard a low, clear whistle, but the sudden glare flashing into my +weary eyes made it impossible for me to tell what it was at which +my friend lashed so savagely. I could, however, see that his face +was deadly pale and filled with horror and loathing. He had +ceased to strike and was gazing up at the ventilator when +suddenly there broke from the silence of the night the most +horrible cry to which I have ever listened. It swelled up louder +and louder, a hoarse yell of pain and fear and anger all mingled +in the one dreadful shriek. They say that away down in the +village, and even in the distant parsonage, that cry raised the +sleepers from their beds. It struck cold to our hearts, and I +stood gazing at Holmes, and he at me, until the last echoes of it +had died away into the silence from which it rose. + +"What can it mean?" I gasped. + +"It means that it is all over," Holmes answered. "And perhaps, +after all, it is for the best. Take your pistol, and we will +enter Dr. Roylott's room." + +With a grave face he lit the lamp and led the way down the +corridor. Twice he struck at the chamber door without any reply +from within. Then he turned the handle and entered, I at his +heels, with the cocked pistol in my hand. + +It was a singular sight which met our eyes. On the table stood a +dark-lantern with the shutter half open, throwing a brilliant +beam of light upon the iron safe, the door of which was ajar. +Beside this table, on the wooden chair, sat Dr. Grimesby Roylott +clad in a long grey dressing-gown, his bare ankles protruding +beneath, and his feet thrust into red heelless Turkish slippers. +Across his lap lay the short stock with the long lash which we +had noticed during the day. His chin was cocked upward and his +eyes were fixed in a dreadful, rigid stare at the corner of the +ceiling. Round his brow he had a peculiar yellow band, with +brownish speckles, which seemed to be bound tightly round his +head. As we entered he made neither sound nor motion. + +"The band! the speckled band!" whispered Holmes. + +I took a step forward. In an instant his strange headgear began +to move, and there reared itself from among his hair the squat +diamond-shaped head and puffed neck of a loathsome serpent. + +"It is a swamp adder!" cried Holmes; "the deadliest snake in +India. He has died within ten seconds of being bitten. Violence +does, in truth, recoil upon the violent, and the schemer falls +into the pit which he digs for another. Let us thrust this +creature back into its den, and we can then remove Miss Stoner to +some place of shelter and let the county police know what has +happened." + +As he spoke he drew the dog-whip swiftly from the dead man's lap, +and throwing the noose round the reptile's neck he drew it from +its horrid perch and, carrying it at arm's length, threw it into +the iron safe, which he closed upon it. + +Such are the true facts of the death of Dr. Grimesby Roylott, of +Stoke Moran. It is not necessary that I should prolong a +narrative which has already run to too great a length by telling +how we broke the sad news to the terrified girl, how we conveyed +her by the morning train to the care of her good aunt at Harrow, +of how the slow process of official inquiry came to the +conclusion that the doctor met his fate while indiscreetly +playing with a dangerous pet. The little which I had yet to learn +of the case was told me by Sherlock Holmes as we travelled back +next day. + +"I had," said he, "come to an entirely erroneous conclusion which +shows, my dear Watson, how dangerous it always is to reason from +insufficient data. The presence of the gipsies, and the use of +the word 'band,' which was used by the poor girl, no doubt, to +explain the appearance which she had caught a hurried glimpse of +by the light of her match, were sufficient to put me upon an +entirely wrong scent. I can only claim the merit that I instantly +reconsidered my position when, however, it became clear to me +that whatever danger threatened an occupant of the room could not +come either from the window or the door. My attention was +speedily drawn, as I have already remarked to you, to this +ventilator, and to the bell-rope which hung down to the bed. The +discovery that this was a dummy, and that the bed was clamped to +the floor, instantly gave rise to the suspicion that the rope was +there as a bridge for something passing through the hole and +coming to the bed. The idea of a snake instantly occurred to me, +and when I coupled it with my knowledge that the doctor was +furnished with a supply of creatures from India, I felt that I +was probably on the right track. The idea of using a form of +poison which could not possibly be discovered by any chemical +test was just such a one as would occur to a clever and ruthless +man who had had an Eastern training. The rapidity with which such +a poison would take effect would also, from his point of view, be +an advantage. It would be a sharp-eyed coroner, indeed, who could +distinguish the two little dark punctures which would show where +the poison fangs had done their work. Then I thought of the +whistle. Of course he must recall the snake before the morning +light revealed it to the victim. He had trained it, probably by +the use of the milk which we saw, to return to him when summoned. +He would put it through this ventilator at the hour that he +thought best, with the certainty that it would crawl down the +rope and land on the bed. It might or might not bite the +occupant, perhaps she might escape every night for a week, but +sooner or later she must fall a victim. + +"I had come to these conclusions before ever I had entered his +room. An inspection of his chair showed me that he had been in +the habit of standing on it, which of course would be necessary +in order that he should reach the ventilator. The sight of the +safe, the saucer of milk, and the loop of whipcord were enough to +finally dispel any doubts which may have remained. The metallic +clang heard by Miss Stoner was obviously caused by her stepfather +hastily closing the door of his safe upon its terrible occupant. +Having once made up my mind, you know the steps which I took in +order to put the matter to the proof. I heard the creature hiss +as I have no doubt that you did also, and I instantly lit the +light and attacked it." + +"With the result of driving it through the ventilator." + +"And also with the result of causing it to turn upon its master +at the other side. Some of the blows of my cane came home and +roused its snakish temper, so that it flew upon the first person +it saw. In this way I am no doubt indirectly responsible for Dr. +Grimesby Roylott's death, and I cannot say that it is likely to +weigh very heavily upon my conscience." + + + +IX. THE ADVENTURE OF THE ENGINEER'S THUMB + +Of all the problems which have been submitted to my friend, Mr. +Sherlock Holmes, for solution during the years of our intimacy, +there were only two which I was the means of introducing to his +notice--that of Mr. Hatherley's thumb, and that of Colonel +Warburton's madness. Of these the latter may have afforded a +finer field for an acute and original observer, but the other was +so strange in its inception and so dramatic in its details that +it may be the more worthy of being placed upon record, even if it +gave my friend fewer openings for those deductive methods of +reasoning by which he achieved such remarkable results. The story +has, I believe, been told more than once in the newspapers, but, +like all such narratives, its effect is much less striking when +set forth en bloc in a single half-column of print than when the +facts slowly evolve before your own eyes, and the mystery clears +gradually away as each new discovery furnishes a step which leads +on to the complete truth. At the time the circumstances made a +deep impression upon me, and the lapse of two years has hardly +served to weaken the effect. + +It was in the summer of '89, not long after my marriage, that the +events occurred which I am now about to summarise. I had returned +to civil practice and had finally abandoned Holmes in his Baker +Street rooms, although I continually visited him and occasionally +even persuaded him to forgo his Bohemian habits so far as to come +and visit us. My practice had steadily increased, and as I +happened to live at no very great distance from Paddington +Station, I got a few patients from among the officials. One of +these, whom I had cured of a painful and lingering disease, was +never weary of advertising my virtues and of endeavouring to send +me on every sufferer over whom he might have any influence. + +One morning, at a little before seven o'clock, I was awakened by +the maid tapping at the door to announce that two men had come +from Paddington and were waiting in the consulting-room. I +dressed hurriedly, for I knew by experience that railway cases +were seldom trivial, and hastened downstairs. As I descended, my +old ally, the guard, came out of the room and closed the door +tightly behind him. + +"I've got him here," he whispered, jerking his thumb over his +shoulder; "he's all right." + +"What is it, then?" I asked, for his manner suggested that it was +some strange creature which he had caged up in my room. + +"It's a new patient," he whispered. "I thought I'd bring him +round myself; then he couldn't slip away. There he is, all safe +and sound. I must go now, Doctor; I have my dooties, just the +same as you." And off he went, this trusty tout, without even +giving me time to thank him. + +I entered my consulting-room and found a gentleman seated by the +table. He was quietly dressed in a suit of heather tweed with a +soft cloth cap which he had laid down upon my books. Round one of +his hands he had a handkerchief wrapped, which was mottled all +over with bloodstains. He was young, not more than +five-and-twenty, I should say, with a strong, masculine face; but +he was exceedingly pale and gave me the impression of a man who +was suffering from some strong agitation, which it took all his +strength of mind to control. + +"I am sorry to knock you up so early, Doctor," said he, "but I +have had a very serious accident during the night. I came in by +train this morning, and on inquiring at Paddington as to where I +might find a doctor, a worthy fellow very kindly escorted me +here. I gave the maid a card, but I see that she has left it upon +the side-table." + +I took it up and glanced at it. "Mr. Victor Hatherley, hydraulic +engineer, 16A, Victoria Street (3rd floor)." That was the name, +style, and abode of my morning visitor. "I regret that I have +kept you waiting," said I, sitting down in my library-chair. "You +are fresh from a night journey, I understand, which is in itself +a monotonous occupation." + +"Oh, my night could not be called monotonous," said he, and +laughed. He laughed very heartily, with a high, ringing note, +leaning back in his chair and shaking his sides. All my medical +instincts rose up against that laugh. + +"Stop it!" I cried; "pull yourself together!" and I poured out +some water from a caraffe. + +It was useless, however. He was off in one of those hysterical +outbursts which come upon a strong nature when some great crisis +is over and gone. Presently he came to himself once more, very +weary and pale-looking. + +"I have been making a fool of myself," he gasped. + +"Not at all. Drink this." I dashed some brandy into the water, +and the colour began to come back to his bloodless cheeks. + +"That's better!" said he. "And now, Doctor, perhaps you would +kindly attend to my thumb, or rather to the place where my thumb +used to be." + +He unwound the handkerchief and held out his hand. It gave even +my hardened nerves a shudder to look at it. There were four +protruding fingers and a horrid red, spongy surface where the +thumb should have been. It had been hacked or torn right out from +the roots. + +"Good heavens!" I cried, "this is a terrible injury. It must have +bled considerably." + +"Yes, it did. I fainted when it was done, and I think that I must +have been senseless for a long time. When I came to I found that +it was still bleeding, so I tied one end of my handkerchief very +tightly round the wrist and braced it up with a twig." + +"Excellent! You should have been a surgeon." + +"It is a question of hydraulics, you see, and came within my own +province." + +"This has been done," said I, examining the wound, "by a very +heavy and sharp instrument." + +"A thing like a cleaver," said he. + +"An accident, I presume?" + +"By no means." + +"What! a murderous attack?" + +"Very murderous indeed." + +"You horrify me." + +I sponged the wound, cleaned it, dressed it, and finally covered +it over with cotton wadding and carbolised bandages. He lay back +without wincing, though he bit his lip from time to time. + +"How is that?" I asked when I had finished. + +"Capital! Between your brandy and your bandage, I feel a new man. +I was very weak, but I have had a good deal to go through." + +"Perhaps you had better not speak of the matter. It is evidently +trying to your nerves." + +"Oh, no, not now. I shall have to tell my tale to the police; +but, between ourselves, if it were not for the convincing +evidence of this wound of mine, I should be surprised if they +believed my statement, for it is a very extraordinary one, and I +have not much in the way of proof with which to back it up; and, +even if they believe me, the clues which I can give them are so +vague that it is a question whether justice will be done." + +"Ha!" cried I, "if it is anything in the nature of a problem +which you desire to see solved, I should strongly recommend you +to come to my friend, Mr. Sherlock Holmes, before you go to the +official police." + +"Oh, I have heard of that fellow," answered my visitor, "and I +should be very glad if he would take the matter up, though of +course I must use the official police as well. Would you give me +an introduction to him?" + +"I'll do better. I'll take you round to him myself." + +"I should be immensely obliged to you." + +"We'll call a cab and go together. We shall just be in time to +have a little breakfast with him. Do you feel equal to it?" + +"Yes; I shall not feel easy until I have told my story." + +"Then my servant will call a cab, and I shall be with you in an +instant." I rushed upstairs, explained the matter shortly to my +wife, and in five minutes was inside a hansom, driving with my +new acquaintance to Baker Street. + +Sherlock Holmes was, as I expected, lounging about his +sitting-room in his dressing-gown, reading the agony column of The +Times and smoking his before-breakfast pipe, which was composed +of all the plugs and dottles left from his smokes of the day +before, all carefully dried and collected on the corner of the +mantelpiece. He received us in his quietly genial fashion, +ordered fresh rashers and eggs, and joined us in a hearty meal. +When it was concluded he settled our new acquaintance upon the +sofa, placed a pillow beneath his head, and laid a glass of +brandy and water within his reach. + +"It is easy to see that your experience has been no common one, +Mr. Hatherley," said he. "Pray, lie down there and make yourself +absolutely at home. Tell us what you can, but stop when you are +tired and keep up your strength with a little stimulant." + +"Thank you," said my patient, "but I have felt another man since +the doctor bandaged me, and I think that your breakfast has +completed the cure. I shall take up as little of your valuable +time as possible, so I shall start at once upon my peculiar +experiences." + +Holmes sat in his big armchair with the weary, heavy-lidded +expression which veiled his keen and eager nature, while I sat +opposite to him, and we listened in silence to the strange story +which our visitor detailed to us. + +"You must know," said he, "that I am an orphan and a bachelor, +residing alone in lodgings in London. By profession I am a +hydraulic engineer, and I have had considerable experience of my +work during the seven years that I was apprenticed to Venner & +Matheson, the well-known firm, of Greenwich. Two years ago, +having served my time, and having also come into a fair sum of +money through my poor father's death, I determined to start in +business for myself and took professional chambers in Victoria +Street. + +"I suppose that everyone finds his first independent start in +business a dreary experience. To me it has been exceptionally so. +During two years I have had three consultations and one small +job, and that is absolutely all that my profession has brought +me. My gross takings amount to 27 pounds 10s. Every day, from +nine in the morning until four in the afternoon, I waited in my +little den, until at last my heart began to sink, and I came to +believe that I should never have any practice at all. + +"Yesterday, however, just as I was thinking of leaving the +office, my clerk entered to say there was a gentleman waiting who +wished to see me upon business. He brought up a card, too, with +the name of 'Colonel Lysander Stark' engraved upon it. Close at +his heels came the colonel himself, a man rather over the middle +size, but of an exceeding thinness. I do not think that I have +ever seen so thin a man. His whole face sharpened away into nose +and chin, and the skin of his cheeks was drawn quite tense over +his outstanding bones. Yet this emaciation seemed to be his +natural habit, and due to no disease, for his eye was bright, his +step brisk, and his bearing assured. He was plainly but neatly +dressed, and his age, I should judge, would be nearer forty than +thirty. + +"'Mr. Hatherley?' said he, with something of a German accent. +'You have been recommended to me, Mr. Hatherley, as being a man +who is not only proficient in his profession but is also discreet +and capable of preserving a secret.' + +"I bowed, feeling as flattered as any young man would at such an +address. 'May I ask who it was who gave me so good a character?' + +"'Well, perhaps it is better that I should not tell you that just +at this moment. I have it from the same source that you are both +an orphan and a bachelor and are residing alone in London.' + +"'That is quite correct,' I answered; 'but you will excuse me if +I say that I cannot see how all this bears upon my professional +qualifications. I understand that it was on a professional matter +that you wished to speak to me?' + +"'Undoubtedly so. But you will find that all I say is really to +the point. I have a professional commission for you, but absolute +secrecy is quite essential--absolute secrecy, you understand, and +of course we may expect that more from a man who is alone than +from one who lives in the bosom of his family.' + +"'If I promise to keep a secret,' said I, 'you may absolutely +depend upon my doing so.' + +"He looked very hard at me as I spoke, and it seemed to me that I +had never seen so suspicious and questioning an eye. + +"'Do you promise, then?' said he at last. + +"'Yes, I promise.' + +"'Absolute and complete silence before, during, and after? No +reference to the matter at all, either in word or writing?' + +"'I have already given you my word.' + +"'Very good.' He suddenly sprang up, and darting like lightning +across the room he flung open the door. The passage outside was +empty. + +"'That's all right,' said he, coming back. 'I know that clerks are +sometimes curious as to their master's affairs. Now we can talk +in safety.' He drew up his chair very close to mine and began to +stare at me again with the same questioning and thoughtful look. + +"A feeling of repulsion, and of something akin to fear had begun +to rise within me at the strange antics of this fleshless man. +Even my dread of losing a client could not restrain me from +showing my impatience. + +"'I beg that you will state your business, sir,' said I; 'my time +is of value.' Heaven forgive me for that last sentence, but the +words came to my lips. + +"'How would fifty guineas for a night's work suit you?' he asked. + +"'Most admirably.' + +"'I say a night's work, but an hour's would be nearer the mark. I +simply want your opinion about a hydraulic stamping machine which +has got out of gear. If you show us what is wrong we shall soon +set it right ourselves. What do you think of such a commission as +that?' + +"'The work appears to be light and the pay munificent.' + +"'Precisely so. We shall want you to come to-night by the last +train.' + +"'Where to?' + +"'To Eyford, in Berkshire. It is a little place near the borders +of Oxfordshire, and within seven miles of Reading. There is a +train from Paddington which would bring you there at about +11:15.' + +"'Very good.' + +"'I shall come down in a carriage to meet you.' + +"'There is a drive, then?' + +"'Yes, our little place is quite out in the country. It is a good +seven miles from Eyford Station.' + +"'Then we can hardly get there before midnight. I suppose there +would be no chance of a train back. I should be compelled to stop +the night.' + +"'Yes, we could easily give you a shake-down.' + +"'That is very awkward. Could I not come at some more convenient +hour?' + +"'We have judged it best that you should come late. It is to +recompense you for any inconvenience that we are paying to you, a +young and unknown man, a fee which would buy an opinion from the +very heads of your profession. Still, of course, if you would +like to draw out of the business, there is plenty of time to do +so.' + +"I thought of the fifty guineas, and of how very useful they +would be to me. 'Not at all,' said I, 'I shall be very happy to +accommodate myself to your wishes. I should like, however, to +understand a little more clearly what it is that you wish me to +do.' + +"'Quite so. It is very natural that the pledge of secrecy which +we have exacted from you should have aroused your curiosity. I +have no wish to commit you to anything without your having it all +laid before you. I suppose that we are absolutely safe from +eavesdroppers?' + +"'Entirely.' + +"'Then the matter stands thus. You are probably aware that +fuller's-earth is a valuable product, and that it is only found +in one or two places in England?' + +"'I have heard so.' + +"'Some little time ago I bought a small place--a very small +place--within ten miles of Reading. I was fortunate enough to +discover that there was a deposit of fuller's-earth in one of my +fields. On examining it, however, I found that this deposit was a +comparatively small one, and that it formed a link between two +very much larger ones upon the right and left--both of them, +however, in the grounds of my neighbours. These good people were +absolutely ignorant that their land contained that which was +quite as valuable as a gold-mine. Naturally, it was to my +interest to buy their land before they discovered its true value, +but unfortunately I had no capital by which I could do this. I +took a few of my friends into the secret, however, and they +suggested that we should quietly and secretly work our own little +deposit and that in this way we should earn the money which would +enable us to buy the neighbouring fields. This we have now been +doing for some time, and in order to help us in our operations we +erected a hydraulic press. This press, as I have already +explained, has got out of order, and we wish your advice upon the +subject. We guard our secret very jealously, however, and if it +once became known that we had hydraulic engineers coming to our +little house, it would soon rouse inquiry, and then, if the facts +came out, it would be good-bye to any chance of getting these +fields and carrying out our plans. That is why I have made you +promise me that you will not tell a human being that you are +going to Eyford to-night. I hope that I make it all plain?' + +"'I quite follow you,' said I. 'The only point which I could not +quite understand was what use you could make of a hydraulic press +in excavating fuller's-earth, which, as I understand, is dug out +like gravel from a pit.' + +"'Ah!' said he carelessly, 'we have our own process. We compress +the earth into bricks, so as to remove them without revealing +what they are. But that is a mere detail. I have taken you fully +into my confidence now, Mr. Hatherley, and I have shown you how I +trust you.' He rose as he spoke. 'I shall expect you, then, at +Eyford at 11:15.' + +"'I shall certainly be there.' + +"'And not a word to a soul.' He looked at me with a last long, +questioning gaze, and then, pressing my hand in a cold, dank +grasp, he hurried from the room. + +"Well, when I came to think it all over in cool blood I was very +much astonished, as you may both think, at this sudden commission +which had been intrusted to me. On the one hand, of course, I was +glad, for the fee was at least tenfold what I should have asked +had I set a price upon my own services, and it was possible that +this order might lead to other ones. On the other hand, the face +and manner of my patron had made an unpleasant impression upon +me, and I could not think that his explanation of the +fuller's-earth was sufficient to explain the necessity for my +coming at midnight, and his extreme anxiety lest I should tell +anyone of my errand. However, I threw all fears to the winds, ate +a hearty supper, drove to Paddington, and started off, having +obeyed to the letter the injunction as to holding my tongue. + +"At Reading I had to change not only my carriage but my station. +However, I was in time for the last train to Eyford, and I +reached the little dim-lit station after eleven o'clock. I was the +only passenger who got out there, and there was no one upon the +platform save a single sleepy porter with a lantern. As I passed +out through the wicket gate, however, I found my acquaintance of +the morning waiting in the shadow upon the other side. Without a +word he grasped my arm and hurried me into a carriage, the door +of which was standing open. He drew up the windows on either +side, tapped on the wood-work, and away we went as fast as the +horse could go." + +"One horse?" interjected Holmes. + +"Yes, only one." + +"Did you observe the colour?" + +"Yes, I saw it by the side-lights when I was stepping into the +carriage. It was a chestnut." + +"Tired-looking or fresh?" + +"Oh, fresh and glossy." + +"Thank you. I am sorry to have interrupted you. Pray continue +your most interesting statement." + +"Away we went then, and we drove for at least an hour. Colonel +Lysander Stark had said that it was only seven miles, but I +should think, from the rate that we seemed to go, and from the +time that we took, that it must have been nearer twelve. He sat +at my side in silence all the time, and I was aware, more than +once when I glanced in his direction, that he was looking at me +with great intensity. The country roads seem to be not very good +in that part of the world, for we lurched and jolted terribly. I +tried to look out of the windows to see something of where we +were, but they were made of frosted glass, and I could make out +nothing save the occasional bright blur of a passing light. Now +and then I hazarded some remark to break the monotony of the +journey, but the colonel answered only in monosyllables, and the +conversation soon flagged. At last, however, the bumping of the +road was exchanged for the crisp smoothness of a gravel-drive, +and the carriage came to a stand. Colonel Lysander Stark sprang +out, and, as I followed after him, pulled me swiftly into a porch +which gaped in front of us. We stepped, as it were, right out of +the carriage and into the hall, so that I failed to catch the +most fleeting glance of the front of the house. The instant that +I had crossed the threshold the door slammed heavily behind us, +and I heard faintly the rattle of the wheels as the carriage +drove away. + +"It was pitch dark inside the house, and the colonel fumbled +about looking for matches and muttering under his breath. +Suddenly a door opened at the other end of the passage, and a +long, golden bar of light shot out in our direction. It grew +broader, and a woman appeared with a lamp in her hand, which she +held above her head, pushing her face forward and peering at us. +I could see that she was pretty, and from the gloss with which +the light shone upon her dark dress I knew that it was a rich +material. She spoke a few words in a foreign tongue in a tone as +though asking a question, and when my companion answered in a +gruff monosyllable she gave such a start that the lamp nearly +fell from her hand. Colonel Stark went up to her, whispered +something in her ear, and then, pushing her back into the room +from whence she had come, he walked towards me again with the +lamp in his hand. + +"'Perhaps you will have the kindness to wait in this room for a +few minutes,' said he, throwing open another door. It was a +quiet, little, plainly furnished room, with a round table in the +centre, on which several German books were scattered. Colonel +Stark laid down the lamp on the top of a harmonium beside the +door. 'I shall not keep you waiting an instant,' said he, and +vanished into the darkness. + +"I glanced at the books upon the table, and in spite of my +ignorance of German I could see that two of them were treatises +on science, the others being volumes of poetry. Then I walked +across to the window, hoping that I might catch some glimpse of +the country-side, but an oak shutter, heavily barred, was folded +across it. It was a wonderfully silent house. There was an old +clock ticking loudly somewhere in the passage, but otherwise +everything was deadly still. A vague feeling of uneasiness began +to steal over me. Who were these German people, and what were +they doing living in this strange, out-of-the-way place? And +where was the place? I was ten miles or so from Eyford, that was +all I knew, but whether north, south, east, or west I had no +idea. For that matter, Reading, and possibly other large towns, +were within that radius, so the place might not be so secluded, +after all. Yet it was quite certain, from the absolute stillness, +that we were in the country. I paced up and down the room, +humming a tune under my breath to keep up my spirits and feeling +that I was thoroughly earning my fifty-guinea fee. + +"Suddenly, without any preliminary sound in the midst of the +utter stillness, the door of my room swung slowly open. The woman +was standing in the aperture, the darkness of the hall behind +her, the yellow light from my lamp beating upon her eager and +beautiful face. I could see at a glance that she was sick with +fear, and the sight sent a chill to my own heart. She held up one +shaking finger to warn me to be silent, and she shot a few +whispered words of broken English at me, her eyes glancing back, +like those of a frightened horse, into the gloom behind her. + +"'I would go,' said she, trying hard, as it seemed to me, to +speak calmly; 'I would go. I should not stay here. There is no +good for you to do.' + +"'But, madam,' said I, 'I have not yet done what I came for. I +cannot possibly leave until I have seen the machine.' + +"'It is not worth your while to wait,' she went on. 'You can pass +through the door; no one hinders.' And then, seeing that I smiled +and shook my head, she suddenly threw aside her constraint and +made a step forward, with her hands wrung together. 'For the love +of Heaven!' she whispered, 'get away from here before it is too +late!' + +"But I am somewhat headstrong by nature, and the more ready to +engage in an affair when there is some obstacle in the way. I +thought of my fifty-guinea fee, of my wearisome journey, and of +the unpleasant night which seemed to be before me. Was it all to +go for nothing? Why should I slink away without having carried +out my commission, and without the payment which was my due? This +woman might, for all I knew, be a monomaniac. With a stout +bearing, therefore, though her manner had shaken me more than I +cared to confess, I still shook my head and declared my intention +of remaining where I was. She was about to renew her entreaties +when a door slammed overhead, and the sound of several footsteps +was heard upon the stairs. She listened for an instant, threw up +her hands with a despairing gesture, and vanished as suddenly and +as noiselessly as she had come. + +"The newcomers were Colonel Lysander Stark and a short thick man +with a chinchilla beard growing out of the creases of his double +chin, who was introduced to me as Mr. Ferguson. + +"'This is my secretary and manager,' said the colonel. 'By the +way, I was under the impression that I left this door shut just +now. I fear that you have felt the draught.' + +"'On the contrary,' said I, 'I opened the door myself because I +felt the room to be a little close.' + +"He shot one of his suspicious looks at me. 'Perhaps we had +better proceed to business, then,' said he. 'Mr. Ferguson and I +will take you up to see the machine.' + +"'I had better put my hat on, I suppose.' + +"'Oh, no, it is in the house.' + +"'What, you dig fuller's-earth in the house?' + +"'No, no. This is only where we compress it. But never mind that. +All we wish you to do is to examine the machine and to let us +know what is wrong with it.' + +"We went upstairs together, the colonel first with the lamp, the +fat manager and I behind him. It was a labyrinth of an old house, +with corridors, passages, narrow winding staircases, and little +low doors, the thresholds of which were hollowed out by the +generations who had crossed them. There were no carpets and no +signs of any furniture above the ground floor, while the plaster +was peeling off the walls, and the damp was breaking through in +green, unhealthy blotches. I tried to put on as unconcerned an +air as possible, but I had not forgotten the warnings of the +lady, even though I disregarded them, and I kept a keen eye upon +my two companions. Ferguson appeared to be a morose and silent +man, but I could see from the little that he said that he was at +least a fellow-countryman. + +"Colonel Lysander Stark stopped at last before a low door, which +he unlocked. Within was a small, square room, in which the three +of us could hardly get at one time. Ferguson remained outside, +and the colonel ushered me in. + +"'We are now,' said he, 'actually within the hydraulic press, and +it would be a particularly unpleasant thing for us if anyone were +to turn it on. The ceiling of this small chamber is really the +end of the descending piston, and it comes down with the force of +many tons upon this metal floor. There are small lateral columns +of water outside which receive the force, and which transmit and +multiply it in the manner which is familiar to you. The machine +goes readily enough, but there is some stiffness in the working +of it, and it has lost a little of its force. Perhaps you will +have the goodness to look it over and to show us how we can set +it right.' + +"I took the lamp from him, and I examined the machine very +thoroughly. It was indeed a gigantic one, and capable of +exercising enormous pressure. When I passed outside, however, and +pressed down the levers which controlled it, I knew at once by +the whishing sound that there was a slight leakage, which allowed +a regurgitation of water through one of the side cylinders. An +examination showed that one of the india-rubber bands which was +round the head of a driving-rod had shrunk so as not quite to +fill the socket along which it worked. This was clearly the cause +of the loss of power, and I pointed it out to my companions, who +followed my remarks very carefully and asked several practical +questions as to how they should proceed to set it right. When I +had made it clear to them, I returned to the main chamber of the +machine and took a good look at it to satisfy my own curiosity. +It was obvious at a glance that the story of the fuller's-earth +was the merest fabrication, for it would be absurd to suppose +that so powerful an engine could be designed for so inadequate a +purpose. The walls were of wood, but the floor consisted of a +large iron trough, and when I came to examine it I could see a +crust of metallic deposit all over it. I had stooped and was +scraping at this to see exactly what it was when I heard a +muttered exclamation in German and saw the cadaverous face of the +colonel looking down at me. + +"'What are you doing there?' he asked. + +"I felt angry at having been tricked by so elaborate a story as +that which he had told me. 'I was admiring your fuller's-earth,' +said I; 'I think that I should be better able to advise you as to +your machine if I knew what the exact purpose was for which it +was used.' + +"The instant that I uttered the words I regretted the rashness of +my speech. His face set hard, and a baleful light sprang up in +his grey eyes. + +"'Very well,' said he, 'you shall know all about the machine.' He +took a step backward, slammed the little door, and turned the key +in the lock. I rushed towards it and pulled at the handle, but it +was quite secure, and did not give in the least to my kicks and +shoves. 'Hullo!' I yelled. 'Hullo! Colonel! Let me out!' + +"And then suddenly in the silence I heard a sound which sent my +heart into my mouth. It was the clank of the levers and the swish +of the leaking cylinder. He had set the engine at work. The lamp +still stood upon the floor where I had placed it when examining +the trough. By its light I saw that the black ceiling was coming +down upon me, slowly, jerkily, but, as none knew better than +myself, with a force which must within a minute grind me to a +shapeless pulp. I threw myself, screaming, against the door, and +dragged with my nails at the lock. I implored the colonel to let +me out, but the remorseless clanking of the levers drowned my +cries. The ceiling was only a foot or two above my head, and with +my hand upraised I could feel its hard, rough surface. Then it +flashed through my mind that the pain of my death would depend +very much upon the position in which I met it. If I lay on my +face the weight would come upon my spine, and I shuddered to +think of that dreadful snap. Easier the other way, perhaps; and +yet, had I the nerve to lie and look up at that deadly black +shadow wavering down upon me? Already I was unable to stand +erect, when my eye caught something which brought a gush of hope +back to my heart. + +"I have said that though the floor and ceiling were of iron, the +walls were of wood. As I gave a last hurried glance around, I saw +a thin line of yellow light between two of the boards, which +broadened and broadened as a small panel was pushed backward. For +an instant I could hardly believe that here was indeed a door +which led away from death. The next instant I threw myself +through, and lay half-fainting upon the other side. The panel had +closed again behind me, but the crash of the lamp, and a few +moments afterwards the clang of the two slabs of metal, told me +how narrow had been my escape. + +"I was recalled to myself by a frantic plucking at my wrist, and +I found myself lying upon the stone floor of a narrow corridor, +while a woman bent over me and tugged at me with her left hand, +while she held a candle in her right. It was the same good friend +whose warning I had so foolishly rejected. + +"'Come! come!' she cried breathlessly. 'They will be here in a +moment. They will see that you are not there. Oh, do not waste +the so-precious time, but come!' + +"This time, at least, I did not scorn her advice. I staggered to +my feet and ran with her along the corridor and down a winding +stair. The latter led to another broad passage, and just as we +reached it we heard the sound of running feet and the shouting of +two voices, one answering the other from the floor on which we +were and from the one beneath. My guide stopped and looked about +her like one who is at her wit's end. Then she threw open a door +which led into a bedroom, through the window of which the moon +was shining brightly. + +"'It is your only chance,' said she. 'It is high, but it may be +that you can jump it.' + +"As she spoke a light sprang into view at the further end of the +passage, and I saw the lean figure of Colonel Lysander Stark +rushing forward with a lantern in one hand and a weapon like a +butcher's cleaver in the other. I rushed across the bedroom, +flung open the window, and looked out. How quiet and sweet and +wholesome the garden looked in the moonlight, and it could not be +more than thirty feet down. I clambered out upon the sill, but I +hesitated to jump until I should have heard what passed between +my saviour and the ruffian who pursued me. If she were ill-used, +then at any risks I was determined to go back to her assistance. +The thought had hardly flashed through my mind before he was at +the door, pushing his way past her; but she threw her arms round +him and tried to hold him back. + +"'Fritz! Fritz!' she cried in English, 'remember your promise +after the last time. You said it should not be again. He will be +silent! Oh, he will be silent!' + +"'You are mad, Elise!' he shouted, struggling to break away from +her. 'You will be the ruin of us. He has seen too much. Let me +pass, I say!' He dashed her to one side, and, rushing to the +window, cut at me with his heavy weapon. I had let myself go, and +was hanging by the hands to the sill, when his blow fell. I was +conscious of a dull pain, my grip loosened, and I fell into the +garden below. + +"I was shaken but not hurt by the fall; so I picked myself up and +rushed off among the bushes as hard as I could run, for I +understood that I was far from being out of danger yet. Suddenly, +however, as I ran, a deadly dizziness and sickness came over me. +I glanced down at my hand, which was throbbing painfully, and +then, for the first time, saw that my thumb had been cut off and +that the blood was pouring from my wound. I endeavoured to tie my +handkerchief round it, but there came a sudden buzzing in my +ears, and next moment I fell in a dead faint among the +rose-bushes. + +"How long I remained unconscious I cannot tell. It must have been +a very long time, for the moon had sunk, and a bright morning was +breaking when I came to myself. My clothes were all sodden with +dew, and my coat-sleeve was drenched with blood from my wounded +thumb. The smarting of it recalled in an instant all the +particulars of my night's adventure, and I sprang to my feet with +the feeling that I might hardly yet be safe from my pursuers. But +to my astonishment, when I came to look round me, neither house +nor garden were to be seen. I had been lying in an angle of the +hedge close by the highroad, and just a little lower down was a +long building, which proved, upon my approaching it, to be the +very station at which I had arrived upon the previous night. Were +it not for the ugly wound upon my hand, all that had passed +during those dreadful hours might have been an evil dream. + +"Half dazed, I went into the station and asked about the morning +train. There would be one to Reading in less than an hour. The +same porter was on duty, I found, as had been there when I +arrived. I inquired of him whether he had ever heard of Colonel +Lysander Stark. The name was strange to him. Had he observed a +carriage the night before waiting for me? No, he had not. Was +there a police-station anywhere near? There was one about three +miles off. + +"It was too far for me to go, weak and ill as I was. I determined +to wait until I got back to town before telling my story to the +police. It was a little past six when I arrived, so I went first +to have my wound dressed, and then the doctor was kind enough to +bring me along here. I put the case into your hands and shall do +exactly what you advise." + +We both sat in silence for some little time after listening to +this extraordinary narrative. Then Sherlock Holmes pulled down +from the shelf one of the ponderous commonplace books in which he +placed his cuttings. + +"Here is an advertisement which will interest you," said he. "It +appeared in all the papers about a year ago. Listen to this: +'Lost, on the 9th inst., Mr. Jeremiah Hayling, aged +twenty-six, a hydraulic engineer. Left his lodgings at ten +o'clock at night, and has not been heard of since. Was +dressed in,' etc., etc. Ha! That represents the last time that +the colonel needed to have his machine overhauled, I fancy." + +"Good heavens!" cried my patient. "Then that explains what the +girl said." + +"Undoubtedly. It is quite clear that the colonel was a cool and +desperate man, who was absolutely determined that nothing should +stand in the way of his little game, like those out-and-out +pirates who will leave no survivor from a captured ship. Well, +every moment now is precious, so if you feel equal to it we shall +go down to Scotland Yard at once as a preliminary to starting for +Eyford." + +Some three hours or so afterwards we were all in the train +together, bound from Reading to the little Berkshire village. +There were Sherlock Holmes, the hydraulic engineer, Inspector +Bradstreet, of Scotland Yard, a plain-clothes man, and myself. +Bradstreet had spread an ordnance map of the county out upon the +seat and was busy with his compasses drawing a circle with Eyford +for its centre. + +"There you are," said he. "That circle is drawn at a radius of +ten miles from the village. The place we want must be somewhere +near that line. You said ten miles, I think, sir." + +"It was an hour's good drive." + +"And you think that they brought you back all that way when you +were unconscious?" + +"They must have done so. I have a confused memory, too, of having +been lifted and conveyed somewhere." + +"What I cannot understand," said I, "is why they should have +spared you when they found you lying fainting in the garden. +Perhaps the villain was softened by the woman's entreaties." + +"I hardly think that likely. I never saw a more inexorable face +in my life." + +"Oh, we shall soon clear up all that," said Bradstreet. "Well, I +have drawn my circle, and I only wish I knew at what point upon +it the folk that we are in search of are to be found." + +"I think I could lay my finger on it," said Holmes quietly. + +"Really, now!" cried the inspector, "you have formed your +opinion! Come, now, we shall see who agrees with you. I say it is +south, for the country is more deserted there." + +"And I say east," said my patient. + +"I am for west," remarked the plain-clothes man. "There are +several quiet little villages up there." + +"And I am for north," said I, "because there are no hills there, +and our friend says that he did not notice the carriage go up +any." + +"Come," cried the inspector, laughing; "it's a very pretty +diversity of opinion. We have boxed the compass among us. Who do +you give your casting vote to?" + +"You are all wrong." + +"But we can't all be." + +"Oh, yes, you can. This is my point." He placed his finger in the +centre of the circle. "This is where we shall find them." + +"But the twelve-mile drive?" gasped Hatherley. + +"Six out and six back. Nothing simpler. You say yourself that the +horse was fresh and glossy when you got in. How could it be that +if it had gone twelve miles over heavy roads?" + +"Indeed, it is a likely ruse enough," observed Bradstreet +thoughtfully. "Of course there can be no doubt as to the nature +of this gang." + +"None at all," said Holmes. "They are coiners on a large scale, +and have used the machine to form the amalgam which has taken the +place of silver." + +"We have known for some time that a clever gang was at work," +said the inspector. "They have been turning out half-crowns by +the thousand. We even traced them as far as Reading, but could +get no farther, for they had covered their traces in a way that +showed that they were very old hands. But now, thanks to this +lucky chance, I think that we have got them right enough." + +But the inspector was mistaken, for those criminals were not +destined to fall into the hands of justice. As we rolled into +Eyford Station we saw a gigantic column of smoke which streamed +up from behind a small clump of trees in the neighbourhood and +hung like an immense ostrich feather over the landscape. + +"A house on fire?" asked Bradstreet as the train steamed off +again on its way. + +"Yes, sir!" said the station-master. + +"When did it break out?" + +"I hear that it was during the night, sir, but it has got worse, +and the whole place is in a blaze." + +"Whose house is it?" + +"Dr. Becher's." + +"Tell me," broke in the engineer, "is Dr. Becher a German, very +thin, with a long, sharp nose?" + +The station-master laughed heartily. "No, sir, Dr. Becher is an +Englishman, and there isn't a man in the parish who has a +better-lined waistcoat. But he has a gentleman staying with him, +a patient, as I understand, who is a foreigner, and he looks as +if a little good Berkshire beef would do him no harm." + +The station-master had not finished his speech before we were all +hastening in the direction of the fire. The road topped a low +hill, and there was a great widespread whitewashed building in +front of us, spouting fire at every chink and window, while in +the garden in front three fire-engines were vainly striving to +keep the flames under. + +"That's it!" cried Hatherley, in intense excitement. "There is +the gravel-drive, and there are the rose-bushes where I lay. That +second window is the one that I jumped from." + +"Well, at least," said Holmes, "you have had your revenge upon +them. There can be no question that it was your oil-lamp which, +when it was crushed in the press, set fire to the wooden walls, +though no doubt they were too excited in the chase after you to +observe it at the time. Now keep your eyes open in this crowd for +your friends of last night, though I very much fear that they are +a good hundred miles off by now." + +And Holmes' fears came to be realised, for from that day to this +no word has ever been heard either of the beautiful woman, the +sinister German, or the morose Englishman. Early that morning a +peasant had met a cart containing several people and some very +bulky boxes driving rapidly in the direction of Reading, but +there all traces of the fugitives disappeared, and even Holmes' +ingenuity failed ever to discover the least clue as to their +whereabouts. + +The firemen had been much perturbed at the strange arrangements +which they had found within, and still more so by discovering a +newly severed human thumb upon a window-sill of the second floor. +About sunset, however, their efforts were at last successful, and +they subdued the flames, but not before the roof had fallen in, +and the whole place been reduced to such absolute ruin that, save +some twisted cylinders and iron piping, not a trace remained of +the machinery which had cost our unfortunate acquaintance so +dearly. Large masses of nickel and of tin were discovered stored +in an out-house, but no coins were to be found, which may have +explained the presence of those bulky boxes which have been +already referred to. + +How our hydraulic engineer had been conveyed from the garden to +the spot where he recovered his senses might have remained +forever a mystery were it not for the soft mould, which told us a +very plain tale. He had evidently been carried down by two +persons, one of whom had remarkably small feet and the other +unusually large ones. On the whole, it was most probable that the +silent Englishman, being less bold or less murderous than his +companion, had assisted the woman to bear the unconscious man out +of the way of danger. + +"Well," said our engineer ruefully as we took our seats to return +once more to London, "it has been a pretty business for me! I +have lost my thumb and I have lost a fifty-guinea fee, and what +have I gained?" + +"Experience," said Holmes, laughing. "Indirectly it may be of +value, you know; you have only to put it into words to gain the +reputation of being excellent company for the remainder of your +existence." + + + +X. THE ADVENTURE OF THE NOBLE BACHELOR + +The Lord St. Simon marriage, and its curious termination, have +long ceased to be a subject of interest in those exalted circles +in which the unfortunate bridegroom moves. Fresh scandals have +eclipsed it, and their more piquant details have drawn the +gossips away from this four-year-old drama. As I have reason to +believe, however, that the full facts have never been revealed to +the general public, and as my friend Sherlock Holmes had a +considerable share in clearing the matter up, I feel that no +memoir of him would be complete without some little sketch of +this remarkable episode. + +It was a few weeks before my own marriage, during the days when I +was still sharing rooms with Holmes in Baker Street, that he came +home from an afternoon stroll to find a letter on the table +waiting for him. I had remained indoors all day, for the weather +had taken a sudden turn to rain, with high autumnal winds, and +the Jezail bullet which I had brought back in one of my limbs as +a relic of my Afghan campaign throbbed with dull persistence. +With my body in one easy-chair and my legs upon another, I had +surrounded myself with a cloud of newspapers until at last, +saturated with the news of the day, I tossed them all aside and +lay listless, watching the huge crest and monogram upon the +envelope upon the table and wondering lazily who my friend's +noble correspondent could be. + +"Here is a very fashionable epistle," I remarked as he entered. +"Your morning letters, if I remember right, were from a +fish-monger and a tide-waiter." + +"Yes, my correspondence has certainly the charm of variety," he +answered, smiling, "and the humbler are usually the more +interesting. This looks like one of those unwelcome social +summonses which call upon a man either to be bored or to lie." + +He broke the seal and glanced over the contents. + +"Oh, come, it may prove to be something of interest, after all." + +"Not social, then?" + +"No, distinctly professional." + +"And from a noble client?" + +"One of the highest in England." + +"My dear fellow, I congratulate you." + +"I assure you, Watson, without affectation, that the status of my +client is a matter of less moment to me than the interest of his +case. It is just possible, however, that that also may not be +wanting in this new investigation. You have been reading the +papers diligently of late, have you not?" + +"It looks like it," said I ruefully, pointing to a huge bundle in +the corner. "I have had nothing else to do." + +"It is fortunate, for you will perhaps be able to post me up. I +read nothing except the criminal news and the agony column. The +latter is always instructive. But if you have followed recent +events so closely you must have read about Lord St. Simon and his +wedding?" + +"Oh, yes, with the deepest interest." + +"That is well. The letter which I hold in my hand is from Lord +St. Simon. I will read it to you, and in return you must turn +over these papers and let me have whatever bears upon the matter. +This is what he says: + +"'MY DEAR MR. SHERLOCK HOLMES:--Lord Backwater tells me that I +may place implicit reliance upon your judgment and discretion. I +have determined, therefore, to call upon you and to consult you +in reference to the very painful event which has occurred in +connection with my wedding. Mr. Lestrade, of Scotland Yard, is +acting already in the matter, but he assures me that he sees no +objection to your co-operation, and that he even thinks that +it might be of some assistance. I will call at four o'clock in +the afternoon, and, should you have any other engagement at that +time, I hope that you will postpone it, as this matter is of +paramount importance. Yours faithfully, ST. SIMON.' + +"It is dated from Grosvenor Mansions, written with a quill pen, +and the noble lord has had the misfortune to get a smear of ink +upon the outer side of his right little finger," remarked Holmes +as he folded up the epistle. + +"He says four o'clock. It is three now. He will be here in an +hour." + +"Then I have just time, with your assistance, to get clear upon +the subject. Turn over those papers and arrange the extracts in +their order of time, while I take a glance as to who our client +is." He picked a red-covered volume from a line of books of +reference beside the mantelpiece. "Here he is," said he, sitting +down and flattening it out upon his knee. "'Lord Robert Walsingham +de Vere St. Simon, second son of the Duke of Balmoral.' Hum! 'Arms: +Azure, three caltrops in chief over a fess sable. Born in 1846.' +He's forty-one years of age, which is mature for marriage. Was +Under-Secretary for the colonies in a late administration. The +Duke, his father, was at one time Secretary for Foreign Affairs. +They inherit Plantagenet blood by direct descent, and Tudor on +the distaff side. Ha! Well, there is nothing very instructive in +all this. I think that I must turn to you Watson, for something +more solid." + +"I have very little difficulty in finding what I want," said I, +"for the facts are quite recent, and the matter struck me as +remarkable. I feared to refer them to you, however, as I knew +that you had an inquiry on hand and that you disliked the +intrusion of other matters." + +"Oh, you mean the little problem of the Grosvenor Square +furniture van. That is quite cleared up now--though, indeed, it +was obvious from the first. Pray give me the results of your +newspaper selections." + +"Here is the first notice which I can find. It is in the personal +column of the Morning Post, and dates, as you see, some weeks +back: 'A marriage has been arranged,' it says, 'and will, if +rumour is correct, very shortly take place, between Lord Robert +St. Simon, second son of the Duke of Balmoral, and Miss Hatty +Doran, the only daughter of Aloysius Doran. Esq., of San +Francisco, Cal., U.S.A.' That is all." + +"Terse and to the point," remarked Holmes, stretching his long, +thin legs towards the fire. + +"There was a paragraph amplifying this in one of the society +papers of the same week. Ah, here it is: 'There will soon be a +call for protection in the marriage market, for the present +free-trade principle appears to tell heavily against our home +product. One by one the management of the noble houses of Great +Britain is passing into the hands of our fair cousins from across +the Atlantic. An important addition has been made during the last +week to the list of the prizes which have been borne away by +these charming invaders. Lord St. Simon, who has shown himself +for over twenty years proof against the little god's arrows, has +now definitely announced his approaching marriage with Miss Hatty +Doran, the fascinating daughter of a California millionaire. Miss +Doran, whose graceful figure and striking face attracted much +attention at the Westbury House festivities, is an only child, +and it is currently reported that her dowry will run to +considerably over the six figures, with expectancies for the +future. As it is an open secret that the Duke of Balmoral has +been compelled to sell his pictures within the last few years, +and as Lord St. Simon has no property of his own save the small +estate of Birchmoor, it is obvious that the Californian heiress +is not the only gainer by an alliance which will enable her to +make the easy and common transition from a Republican lady to a +British peeress.'" + +"Anything else?" asked Holmes, yawning. + +"Oh, yes; plenty. Then there is another note in the Morning Post +to say that the marriage would be an absolutely quiet one, that it +would be at St. George's, Hanover Square, that only half a dozen +intimate friends would be invited, and that the party would +return to the furnished house at Lancaster Gate which has been +taken by Mr. Aloysius Doran. Two days later--that is, on +Wednesday last--there is a curt announcement that the wedding had +taken place, and that the honeymoon would be passed at Lord +Backwater's place, near Petersfield. Those are all the notices +which appeared before the disappearance of the bride." + +"Before the what?" asked Holmes with a start. + +"The vanishing of the lady." + +"When did she vanish, then?" + +"At the wedding breakfast." + +"Indeed. This is more interesting than it promised to be; quite +dramatic, in fact." + +"Yes; it struck me as being a little out of the common." + +"They often vanish before the ceremony, and occasionally during +the honeymoon; but I cannot call to mind anything quite so prompt +as this. Pray let me have the details." + +"I warn you that they are very incomplete." + +"Perhaps we may make them less so." + +"Such as they are, they are set forth in a single article of a +morning paper of yesterday, which I will read to you. It is +headed, 'Singular Occurrence at a Fashionable Wedding': + +"'The family of Lord Robert St. Simon has been thrown into the +greatest consternation by the strange and painful episodes which +have taken place in connection with his wedding. The ceremony, as +shortly announced in the papers of yesterday, occurred on the +previous morning; but it is only now that it has been possible to +confirm the strange rumours which have been so persistently +floating about. In spite of the attempts of the friends to hush +the matter up, so much public attention has now been drawn to it +that no good purpose can be served by affecting to disregard what +is a common subject for conversation. + +"'The ceremony, which was performed at St. George's, Hanover +Square, was a very quiet one, no one being present save the +father of the bride, Mr. Aloysius Doran, the Duchess of Balmoral, +Lord Backwater, Lord Eustace and Lady Clara St. Simon (the +younger brother and sister of the bridegroom), and Lady Alicia +Whittington. The whole party proceeded afterwards to the house of +Mr. Aloysius Doran, at Lancaster Gate, where breakfast had been +prepared. It appears that some little trouble was caused by a +woman, whose name has not been ascertained, who endeavoured to +force her way into the house after the bridal party, alleging +that she had some claim upon Lord St. Simon. It was only after a +painful and prolonged scene that she was ejected by the butler +and the footman. The bride, who had fortunately entered the house +before this unpleasant interruption, had sat down to breakfast +with the rest, when she complained of a sudden indisposition and +retired to her room. Her prolonged absence having caused some +comment, her father followed her, but learned from her maid that +she had only come up to her chamber for an instant, caught up an +ulster and bonnet, and hurried down to the passage. One of the +footmen declared that he had seen a lady leave the house thus +apparelled, but had refused to credit that it was his mistress, +believing her to be with the company. On ascertaining that his +daughter had disappeared, Mr. Aloysius Doran, in conjunction with +the bridegroom, instantly put themselves in communication with +the police, and very energetic inquiries are being made, which +will probably result in a speedy clearing up of this very +singular business. Up to a late hour last night, however, nothing +had transpired as to the whereabouts of the missing lady. There +are rumours of foul play in the matter, and it is said that the +police have caused the arrest of the woman who had caused the +original disturbance, in the belief that, from jealousy or some +other motive, she may have been concerned in the strange +disappearance of the bride.'" + +"And is that all?" + +"Only one little item in another of the morning papers, but it is +a suggestive one." + +"And it is--" + +"That Miss Flora Millar, the lady who had caused the disturbance, +has actually been arrested. It appears that she was formerly a +danseuse at the Allegro, and that she has known the bridegroom +for some years. There are no further particulars, and the whole +case is in your hands now--so far as it has been set forth in the +public press." + +"And an exceedingly interesting case it appears to be. I would +not have missed it for worlds. But there is a ring at the bell, +Watson, and as the clock makes it a few minutes after four, I +have no doubt that this will prove to be our noble client. Do not +dream of going, Watson, for I very much prefer having a witness, +if only as a check to my own memory." + +"Lord Robert St. Simon," announced our page-boy, throwing open +the door. A gentleman entered, with a pleasant, cultured face, +high-nosed and pale, with something perhaps of petulance about +the mouth, and with the steady, well-opened eye of a man whose +pleasant lot it had ever been to command and to be obeyed. His +manner was brisk, and yet his general appearance gave an undue +impression of age, for he had a slight forward stoop and a little +bend of the knees as he walked. His hair, too, as he swept off +his very curly-brimmed hat, was grizzled round the edges and thin +upon the top. As to his dress, it was careful to the verge of +foppishness, with high collar, black frock-coat, white waistcoat, +yellow gloves, patent-leather shoes, and light-coloured gaiters. +He advanced slowly into the room, turning his head from left to +right, and swinging in his right hand the cord which held his +golden eyeglasses. + +"Good-day, Lord St. Simon," said Holmes, rising and bowing. "Pray +take the basket-chair. This is my friend and colleague, Dr. +Watson. Draw up a little to the fire, and we will talk this +matter over." + +"A most painful matter to me, as you can most readily imagine, +Mr. Holmes. I have been cut to the quick. I understand that you +have already managed several delicate cases of this sort, sir, +though I presume that they were hardly from the same class of +society." + +"No, I am descending." + +"I beg pardon." + +"My last client of the sort was a king." + +"Oh, really! I had no idea. And which king?" + +"The King of Scandinavia." + +"What! Had he lost his wife?" + +"You can understand," said Holmes suavely, "that I extend to the +affairs of my other clients the same secrecy which I promise to +you in yours." + +"Of course! Very right! very right! I'm sure I beg pardon. As to +my own case, I am ready to give you any information which may +assist you in forming an opinion." + +"Thank you. I have already learned all that is in the public +prints, nothing more. I presume that I may take it as correct--this +article, for example, as to the disappearance of the bride." + +Lord St. Simon glanced over it. "Yes, it is correct, as far as it +goes." + +"But it needs a great deal of supplementing before anyone could +offer an opinion. I think that I may arrive at my facts most +directly by questioning you." + +"Pray do so." + +"When did you first meet Miss Hatty Doran?" + +"In San Francisco, a year ago." + +"You were travelling in the States?" + +"Yes." + +"Did you become engaged then?" + +"No." + +"But you were on a friendly footing?" + +"I was amused by her society, and she could see that I was +amused." + +"Her father is very rich?" + +"He is said to be the richest man on the Pacific slope." + +"And how did he make his money?" + +"In mining. He had nothing a few years ago. Then he struck gold, +invested it, and came up by leaps and bounds." + +"Now, what is your own impression as to the young lady's--your +wife's character?" + +The nobleman swung his glasses a little faster and stared down +into the fire. "You see, Mr. Holmes," said he, "my wife was +twenty before her father became a rich man. During that time she +ran free in a mining camp and wandered through woods or +mountains, so that her education has come from Nature rather than +from the schoolmaster. She is what we call in England a tomboy, +with a strong nature, wild and free, unfettered by any sort of +traditions. She is impetuous--volcanic, I was about to say. She +is swift in making up her mind and fearless in carrying out her +resolutions. On the other hand, I would not have given her the +name which I have the honour to bear"--he gave a little stately +cough--"had not I thought her to be at bottom a noble woman. I +believe that she is capable of heroic self-sacrifice and that +anything dishonourable would be repugnant to her." + +"Have you her photograph?" + +"I brought this with me." He opened a locket and showed us the +full face of a very lovely woman. It was not a photograph but an +ivory miniature, and the artist had brought out the full effect +of the lustrous black hair, the large dark eyes, and the +exquisite mouth. Holmes gazed long and earnestly at it. Then he +closed the locket and handed it back to Lord St. Simon. + +"The young lady came to London, then, and you renewed your +acquaintance?" + +"Yes, her father brought her over for this last London season. I +met her several times, became engaged to her, and have now +married her." + +"She brought, I understand, a considerable dowry?" + +"A fair dowry. Not more than is usual in my family." + +"And this, of course, remains to you, since the marriage is a +fait accompli?" + +"I really have made no inquiries on the subject." + +"Very naturally not. Did you see Miss Doran on the day before the +wedding?" + +"Yes." + +"Was she in good spirits?" + +"Never better. She kept talking of what we should do in our +future lives." + +"Indeed! That is very interesting. And on the morning of the +wedding?" + +"She was as bright as possible--at least until after the +ceremony." + +"And did you observe any change in her then?" + +"Well, to tell the truth, I saw then the first signs that I had +ever seen that her temper was just a little sharp. The incident +however, was too trivial to relate and can have no possible +bearing upon the case." + +"Pray let us have it, for all that." + +"Oh, it is childish. She dropped her bouquet as we went towards +the vestry. She was passing the front pew at the time, and it +fell over into the pew. There was a moment's delay, but the +gentleman in the pew handed it up to her again, and it did not +appear to be the worse for the fall. Yet when I spoke to her of +the matter, she answered me abruptly; and in the carriage, on our +way home, she seemed absurdly agitated over this trifling cause." + +"Indeed! You say that there was a gentleman in the pew. Some of +the general public were present, then?" + +"Oh, yes. It is impossible to exclude them when the church is +open." + +"This gentleman was not one of your wife's friends?" + +"No, no; I call him a gentleman by courtesy, but he was quite a +common-looking person. I hardly noticed his appearance. But +really I think that we are wandering rather far from the point." + +"Lady St. Simon, then, returned from the wedding in a less +cheerful frame of mind than she had gone to it. What did she do +on re-entering her father's house?" + +"I saw her in conversation with her maid." + +"And who is her maid?" + +"Alice is her name. She is an American and came from California +with her." + +"A confidential servant?" + +"A little too much so. It seemed to me that her mistress allowed +her to take great liberties. Still, of course, in America they +look upon these things in a different way." + +"How long did she speak to this Alice?" + +"Oh, a few minutes. I had something else to think of." + +"You did not overhear what they said?" + +"Lady St. Simon said something about 'jumping a claim.' She was +accustomed to use slang of the kind. I have no idea what she +meant." + +"American slang is very expressive sometimes. And what did your +wife do when she finished speaking to her maid?" + +"She walked into the breakfast-room." + +"On your arm?" + +"No, alone. She was very independent in little matters like that. +Then, after we had sat down for ten minutes or so, she rose +hurriedly, muttered some words of apology, and left the room. She +never came back." + +"But this maid, Alice, as I understand, deposes that she went to +her room, covered her bride's dress with a long ulster, put on a +bonnet, and went out." + +"Quite so. And she was afterwards seen walking into Hyde Park in +company with Flora Millar, a woman who is now in custody, and who +had already made a disturbance at Mr. Doran's house that +morning." + +"Ah, yes. I should like a few particulars as to this young lady, +and your relations to her." + +Lord St. Simon shrugged his shoulders and raised his eyebrows. +"We have been on a friendly footing for some years--I may say on +a very friendly footing. She used to be at the Allegro. I have +not treated her ungenerously, and she had no just cause of +complaint against me, but you know what women are, Mr. Holmes. +Flora was a dear little thing, but exceedingly hot-headed and +devotedly attached to me. She wrote me dreadful letters when she +heard that I was about to be married, and, to tell the truth, the +reason why I had the marriage celebrated so quietly was that I +feared lest there might be a scandal in the church. She came to +Mr. Doran's door just after we returned, and she endeavoured to +push her way in, uttering very abusive expressions towards my +wife, and even threatening her, but I had foreseen the +possibility of something of the sort, and I had two police +fellows there in private clothes, who soon pushed her out again. +She was quiet when she saw that there was no good in making a +row." + +"Did your wife hear all this?" + +"No, thank goodness, she did not." + +"And she was seen walking with this very woman afterwards?" + +"Yes. That is what Mr. Lestrade, of Scotland Yard, looks upon as +so serious. It is thought that Flora decoyed my wife out and laid +some terrible trap for her." + +"Well, it is a possible supposition." + +"You think so, too?" + +"I did not say a probable one. But you do not yourself look upon +this as likely?" + +"I do not think Flora would hurt a fly." + +"Still, jealousy is a strange transformer of characters. Pray +what is your own theory as to what took place?" + +"Well, really, I came to seek a theory, not to propound one. I +have given you all the facts. Since you ask me, however, I may +say that it has occurred to me as possible that the excitement of +this affair, the consciousness that she had made so immense a +social stride, had the effect of causing some little nervous +disturbance in my wife." + +"In short, that she had become suddenly deranged?" + +"Well, really, when I consider that she has turned her back--I +will not say upon me, but upon so much that many have aspired to +without success--I can hardly explain it in any other fashion." + +"Well, certainly that is also a conceivable hypothesis," said +Holmes, smiling. "And now, Lord St. Simon, I think that I have +nearly all my data. May I ask whether you were seated at the +breakfast-table so that you could see out of the window?" + +"We could see the other side of the road and the Park." + +"Quite so. Then I do not think that I need to detain you longer. +I shall communicate with you." + +"Should you be fortunate enough to solve this problem," said our +client, rising. + +"I have solved it." + +"Eh? What was that?" + +"I say that I have solved it." + +"Where, then, is my wife?" + +"That is a detail which I shall speedily supply." + +Lord St. Simon shook his head. "I am afraid that it will take +wiser heads than yours or mine," he remarked, and bowing in a +stately, old-fashioned manner he departed. + +"It is very good of Lord St. Simon to honour my head by putting +it on a level with his own," said Sherlock Holmes, laughing. "I +think that I shall have a whisky and soda and a cigar after all +this cross-questioning. I had formed my conclusions as to the +case before our client came into the room." + +"My dear Holmes!" + +"I have notes of several similar cases, though none, as I +remarked before, which were quite as prompt. My whole examination +served to turn my conjecture into a certainty. Circumstantial +evidence is occasionally very convincing, as when you find a +trout in the milk, to quote Thoreau's example." + +"But I have heard all that you have heard." + +"Without, however, the knowledge of pre-existing cases which +serves me so well. There was a parallel instance in Aberdeen some +years back, and something on very much the same lines at Munich +the year after the Franco-Prussian War. It is one of these +cases--but, hullo, here is Lestrade! Good-afternoon, Lestrade! +You will find an extra tumbler upon the sideboard, and there are +cigars in the box." + +The official detective was attired in a pea-jacket and cravat, +which gave him a decidedly nautical appearance, and he carried a +black canvas bag in his hand. With a short greeting he seated +himself and lit the cigar which had been offered to him. + +"What's up, then?" asked Holmes with a twinkle in his eye. "You +look dissatisfied." + +"And I feel dissatisfied. It is this infernal St. Simon marriage +case. I can make neither head nor tail of the business." + +"Really! You surprise me." + +"Who ever heard of such a mixed affair? Every clue seems to slip +through my fingers. I have been at work upon it all day." + +"And very wet it seems to have made you," said Holmes laying his +hand upon the arm of the pea-jacket. + +"Yes, I have been dragging the Serpentine." + +"In heaven's name, what for?" + +"In search of the body of Lady St. Simon." + +Sherlock Holmes leaned back in his chair and laughed heartily. + +"Have you dragged the basin of Trafalgar Square fountain?" he +asked. + +"Why? What do you mean?" + +"Because you have just as good a chance of finding this lady in +the one as in the other." + +Lestrade shot an angry glance at my companion. "I suppose you +know all about it," he snarled. + +"Well, I have only just heard the facts, but my mind is made up." + +"Oh, indeed! Then you think that the Serpentine plays no part in +the matter?" + +"I think it very unlikely." + +"Then perhaps you will kindly explain how it is that we found +this in it?" He opened his bag as he spoke, and tumbled onto the +floor a wedding-dress of watered silk, a pair of white satin +shoes and a bride's wreath and veil, all discoloured and soaked +in water. "There," said he, putting a new wedding-ring upon the +top of the pile. "There is a little nut for you to crack, Master +Holmes." + +"Oh, indeed!" said my friend, blowing blue rings into the air. +"You dragged them from the Serpentine?" + +"No. They were found floating near the margin by a park-keeper. +They have been identified as her clothes, and it seemed to me +that if the clothes were there the body would not be far off." + +"By the same brilliant reasoning, every man's body is to be found +in the neighbourhood of his wardrobe. And pray what did you hope +to arrive at through this?" + +"At some evidence implicating Flora Millar in the disappearance." + +"I am afraid that you will find it difficult." + +"Are you, indeed, now?" cried Lestrade with some bitterness. "I +am afraid, Holmes, that you are not very practical with your +deductions and your inferences. You have made two blunders in as +many minutes. This dress does implicate Miss Flora Millar." + +"And how?" + +"In the dress is a pocket. In the pocket is a card-case. In the +card-case is a note. And here is the very note." He slapped it +down upon the table in front of him. "Listen to this: 'You will +see me when all is ready. Come at once. F.H.M.' Now my theory all +along has been that Lady St. Simon was decoyed away by Flora +Millar, and that she, with confederates, no doubt, was +responsible for her disappearance. Here, signed with her +initials, is the very note which was no doubt quietly slipped +into her hand at the door and which lured her within their +reach." + +"Very good, Lestrade," said Holmes, laughing. "You really are +very fine indeed. Let me see it." He took up the paper in a +listless way, but his attention instantly became riveted, and he +gave a little cry of satisfaction. "This is indeed important," +said he. + +"Ha! you find it so?" + +"Extremely so. I congratulate you warmly." + +Lestrade rose in his triumph and bent his head to look. "Why," he +shrieked, "you're looking at the wrong side!" + +"On the contrary, this is the right side." + +"The right side? You're mad! Here is the note written in pencil +over here." + +"And over here is what appears to be the fragment of a hotel +bill, which interests me deeply." + +"There's nothing in it. I looked at it before," said Lestrade. +"'Oct. 4th, rooms 8s., breakfast 2s. 6d., cocktail 1s., lunch 2s. +6d., glass sherry, 8d.' I see nothing in that." + +"Very likely not. It is most important, all the same. As to the +note, it is important also, or at least the initials are, so I +congratulate you again." + +"I've wasted time enough," said Lestrade, rising. "I believe in +hard work and not in sitting by the fire spinning fine theories. +Good-day, Mr. Holmes, and we shall see which gets to the bottom +of the matter first." He gathered up the garments, thrust them +into the bag, and made for the door. + +"Just one hint to you, Lestrade," drawled Holmes before his rival +vanished; "I will tell you the true solution of the matter. Lady +St. Simon is a myth. There is not, and there never has been, any +such person." + +Lestrade looked sadly at my companion. Then he turned to me, +tapped his forehead three times, shook his head solemnly, and +hurried away. + +He had hardly shut the door behind him when Holmes rose to put on +his overcoat. "There is something in what the fellow says about +outdoor work," he remarked, "so I think, Watson, that I must +leave you to your papers for a little." + +It was after five o'clock when Sherlock Holmes left me, but I had +no time to be lonely, for within an hour there arrived a +confectioner's man with a very large flat box. This he unpacked +with the help of a youth whom he had brought with him, and +presently, to my very great astonishment, a quite epicurean +little cold supper began to be laid out upon our humble +lodging-house mahogany. There were a couple of brace of cold +woodcock, a pheasant, a pâté de foie gras pie with a group of +ancient and cobwebby bottles. Having laid out all these luxuries, +my two visitors vanished away, like the genii of the Arabian +Nights, with no explanation save that the things had been paid +for and were ordered to this address. + +Just before nine o'clock Sherlock Holmes stepped briskly into the +room. His features were gravely set, but there was a light in his +eye which made me think that he had not been disappointed in his +conclusions. + +"They have laid the supper, then," he said, rubbing his hands. + +"You seem to expect company. They have laid for five." + +"Yes, I fancy we may have some company dropping in," said he. "I +am surprised that Lord St. Simon has not already arrived. Ha! I +fancy that I hear his step now upon the stairs." + +It was indeed our visitor of the afternoon who came bustling in, +dangling his glasses more vigorously than ever, and with a very +perturbed expression upon his aristocratic features. + +"My messenger reached you, then?" asked Holmes. + +"Yes, and I confess that the contents startled me beyond measure. +Have you good authority for what you say?" + +"The best possible." + +Lord St. Simon sank into a chair and passed his hand over his +forehead. + +"What will the Duke say," he murmured, "when he hears that one of +the family has been subjected to such humiliation?" + +"It is the purest accident. I cannot allow that there is any +humiliation." + +"Ah, you look on these things from another standpoint." + +"I fail to see that anyone is to blame. I can hardly see how the +lady could have acted otherwise, though her abrupt method of +doing it was undoubtedly to be regretted. Having no mother, she +had no one to advise her at such a crisis." + +"It was a slight, sir, a public slight," said Lord St. Simon, +tapping his fingers upon the table. + +"You must make allowance for this poor girl, placed in so +unprecedented a position." + +"I will make no allowance. I am very angry indeed, and I have +been shamefully used." + +"I think that I heard a ring," said Holmes. "Yes, there are steps +on the landing. If I cannot persuade you to take a lenient view +of the matter, Lord St. Simon, I have brought an advocate here +who may be more successful." He opened the door and ushered in a +lady and gentleman. "Lord St. Simon," said he "allow me to +introduce you to Mr. and Mrs. Francis Hay Moulton. The lady, I +think, you have already met." + +At the sight of these newcomers our client had sprung from his +seat and stood very erect, with his eyes cast down and his hand +thrust into the breast of his frock-coat, a picture of offended +dignity. The lady had taken a quick step forward and had held out +her hand to him, but he still refused to raise his eyes. It was +as well for his resolution, perhaps, for her pleading face was +one which it was hard to resist. + +"You're angry, Robert," said she. "Well, I guess you have every +cause to be." + +"Pray make no apology to me," said Lord St. Simon bitterly. + +"Oh, yes, I know that I have treated you real bad and that I +should have spoken to you before I went; but I was kind of +rattled, and from the time when I saw Frank here again I just +didn't know what I was doing or saying. I only wonder I didn't +fall down and do a faint right there before the altar." + +"Perhaps, Mrs. Moulton, you would like my friend and me to leave +the room while you explain this matter?" + +"If I may give an opinion," remarked the strange gentleman, +"we've had just a little too much secrecy over this business +already. For my part, I should like all Europe and America to +hear the rights of it." He was a small, wiry, sunburnt man, +clean-shaven, with a sharp face and alert manner. + +"Then I'll tell our story right away," said the lady. "Frank here +and I met in '84, in McQuire's camp, near the Rockies, where pa +was working a claim. We were engaged to each other, Frank and I; +but then one day father struck a rich pocket and made a pile, +while poor Frank here had a claim that petered out and came to +nothing. The richer pa grew the poorer was Frank; so at last pa +wouldn't hear of our engagement lasting any longer, and he took +me away to 'Frisco. Frank wouldn't throw up his hand, though; so +he followed me there, and he saw me without pa knowing anything +about it. It would only have made him mad to know, so we just +fixed it all up for ourselves. Frank said that he would go and +make his pile, too, and never come back to claim me until he had +as much as pa. So then I promised to wait for him to the end of +time and pledged myself not to marry anyone else while he lived. +'Why shouldn't we be married right away, then,' said he, 'and +then I will feel sure of you; and I won't claim to be your +husband until I come back?' Well, we talked it over, and he had +fixed it all up so nicely, with a clergyman all ready in waiting, +that we just did it right there; and then Frank went off to seek +his fortune, and I went back to pa. + +"The next I heard of Frank was that he was in Montana, and then +he went prospecting in Arizona, and then I heard of him from New +Mexico. After that came a long newspaper story about how a +miners' camp had been attacked by Apache Indians, and there was +my Frank's name among the killed. I fainted dead away, and I was +very sick for months after. Pa thought I had a decline and took +me to half the doctors in 'Frisco. Not a word of news came for a +year and more, so that I never doubted that Frank was really +dead. Then Lord St. Simon came to 'Frisco, and we came to London, +and a marriage was arranged, and pa was very pleased, but I felt +all the time that no man on this earth would ever take the place +in my heart that had been given to my poor Frank. + +"Still, if I had married Lord St. Simon, of course I'd have done +my duty by him. We can't command our love, but we can our +actions. I went to the altar with him with the intention to make +him just as good a wife as it was in me to be. But you may +imagine what I felt when, just as I came to the altar rails, I +glanced back and saw Frank standing and looking at me out of the +first pew. I thought it was his ghost at first; but when I looked +again there he was still, with a kind of question in his eyes, as +if to ask me whether I were glad or sorry to see him. I wonder I +didn't drop. I know that everything was turning round, and the +words of the clergyman were just like the buzz of a bee in my +ear. I didn't know what to do. Should I stop the service and make +a scene in the church? I glanced at him again, and he seemed to +know what I was thinking, for he raised his finger to his lips to +tell me to be still. Then I saw him scribble on a piece of paper, +and I knew that he was writing me a note. As I passed his pew on +the way out I dropped my bouquet over to him, and he slipped the +note into my hand when he returned me the flowers. It was only a +line asking me to join him when he made the sign to me to do so. +Of course I never doubted for a moment that my first duty was now +to him, and I determined to do just whatever he might direct. + +"When I got back I told my maid, who had known him in California, +and had always been his friend. I ordered her to say nothing, but +to get a few things packed and my ulster ready. I know I ought to +have spoken to Lord St. Simon, but it was dreadful hard before +his mother and all those great people. I just made up my mind to +run away and explain afterwards. I hadn't been at the table ten +minutes before I saw Frank out of the window at the other side of +the road. He beckoned to me and then began walking into the Park. +I slipped out, put on my things, and followed him. Some woman +came talking something or other about Lord St. Simon to +me--seemed to me from the little I heard as if he had a little +secret of his own before marriage also--but I managed to get away +from her and soon overtook Frank. We got into a cab together, and +away we drove to some lodgings he had taken in Gordon Square, and +that was my true wedding after all those years of waiting. Frank +had been a prisoner among the Apaches, had escaped, came on to +'Frisco, found that I had given him up for dead and had gone to +England, followed me there, and had come upon me at last on the +very morning of my second wedding." + +"I saw it in a paper," explained the American. "It gave the name +and the church but not where the lady lived." + +"Then we had a talk as to what we should do, and Frank was all +for openness, but I was so ashamed of it all that I felt as if I +should like to vanish away and never see any of them again--just +sending a line to pa, perhaps, to show him that I was alive. It +was awful to me to think of all those lords and ladies sitting +round that breakfast-table and waiting for me to come back. So +Frank took my wedding-clothes and things and made a bundle of +them, so that I should not be traced, and dropped them away +somewhere where no one could find them. It is likely that we +should have gone on to Paris to-morrow, only that this good +gentleman, Mr. Holmes, came round to us this evening, though how +he found us is more than I can think, and he showed us very +clearly and kindly that I was wrong and that Frank was right, and +that we should be putting ourselves in the wrong if we were so +secret. Then he offered to give us a chance of talking to Lord +St. Simon alone, and so we came right away round to his rooms at +once. Now, Robert, you have heard it all, and I am very sorry if +I have given you pain, and I hope that you do not think very +meanly of me." + +Lord St. Simon had by no means relaxed his rigid attitude, but +had listened with a frowning brow and a compressed lip to this +long narrative. + +"Excuse me," he said, "but it is not my custom to discuss my most +intimate personal affairs in this public manner." + +"Then you won't forgive me? You won't shake hands before I go?" + +"Oh, certainly, if it would give you any pleasure." He put out +his hand and coldly grasped that which she extended to him. + +"I had hoped," suggested Holmes, "that you would have joined us +in a friendly supper." + +"I think that there you ask a little too much," responded his +Lordship. "I may be forced to acquiesce in these recent +developments, but I can hardly be expected to make merry over +them. I think that with your permission I will now wish you all a +very good-night." He included us all in a sweeping bow and +stalked out of the room. + +"Then I trust that you at least will honour me with your +company," said Sherlock Holmes. "It is always a joy to meet an +American, Mr. Moulton, for I am one of those who believe that the +folly of a monarch and the blundering of a minister in far-gone +years will not prevent our children from being some day citizens +of the same world-wide country under a flag which shall be a +quartering of the Union Jack with the Stars and Stripes." + +"The case has been an interesting one," remarked Holmes when our +visitors had left us, "because it serves to show very clearly how +simple the explanation may be of an affair which at first sight +seems to be almost inexplicable. Nothing could be more natural +than the sequence of events as narrated by this lady, and nothing +stranger than the result when viewed, for instance, by Mr. +Lestrade of Scotland Yard." + +"You were not yourself at fault at all, then?" + +"From the first, two facts were very obvious to me, the one that +the lady had been quite willing to undergo the wedding ceremony, +the other that she had repented of it within a few minutes of +returning home. Obviously something had occurred during the +morning, then, to cause her to change her mind. What could that +something be? She could not have spoken to anyone when she was +out, for she had been in the company of the bridegroom. Had she +seen someone, then? If she had, it must be someone from America +because she had spent so short a time in this country that she +could hardly have allowed anyone to acquire so deep an influence +over her that the mere sight of him would induce her to change +her plans so completely. You see we have already arrived, by a +process of exclusion, at the idea that she might have seen an +American. Then who could this American be, and why should he +possess so much influence over her? It might be a lover; it might +be a husband. Her young womanhood had, I knew, been spent in +rough scenes and under strange conditions. So far I had got +before I ever heard Lord St. Simon's narrative. When he told us +of a man in a pew, of the change in the bride's manner, of so +transparent a device for obtaining a note as the dropping of a +bouquet, of her resort to her confidential maid, and of her very +significant allusion to claim-jumping--which in miners' parlance +means taking possession of that which another person has a prior +claim to--the whole situation became absolutely clear. She had +gone off with a man, and the man was either a lover or was a +previous husband--the chances being in favour of the latter." + +"And how in the world did you find them?" + +"It might have been difficult, but friend Lestrade held +information in his hands the value of which he did not himself +know. The initials were, of course, of the highest importance, +but more valuable still was it to know that within a week he had +settled his bill at one of the most select London hotels." + +"How did you deduce the select?" + +"By the select prices. Eight shillings for a bed and eightpence +for a glass of sherry pointed to one of the most expensive +hotels. There are not many in London which charge at that rate. +In the second one which I visited in Northumberland Avenue, I +learned by an inspection of the book that Francis H. Moulton, an +American gentleman, had left only the day before, and on looking +over the entries against him, I came upon the very items which I +had seen in the duplicate bill. His letters were to be forwarded +to 226 Gordon Square; so thither I travelled, and being fortunate +enough to find the loving couple at home, I ventured to give them +some paternal advice and to point out to them that it would be +better in every way that they should make their position a little +clearer both to the general public and to Lord St. Simon in +particular. I invited them to meet him here, and, as you see, I +made him keep the appointment." + +"But with no very good result," I remarked. "His conduct was +certainly not very gracious." + +"Ah, Watson," said Holmes, smiling, "perhaps you would not be +very gracious either, if, after all the trouble of wooing and +wedding, you found yourself deprived in an instant of wife and of +fortune. I think that we may judge Lord St. Simon very mercifully +and thank our stars that we are never likely to find ourselves in +the same position. Draw your chair up and hand me my violin, for +the only problem we have still to solve is how to while away +these bleak autumnal evenings." + + + +XI. THE ADVENTURE OF THE BERYL CORONET + +"Holmes," said I as I stood one morning in our bow-window looking +down the street, "here is a madman coming along. It seems rather +sad that his relatives should allow him to come out alone." + +My friend rose lazily from his armchair and stood with his hands +in the pockets of his dressing-gown, looking over my shoulder. It +was a bright, crisp February morning, and the snow of the day +before still lay deep upon the ground, shimmering brightly in the +wintry sun. Down the centre of Baker Street it had been ploughed +into a brown crumbly band by the traffic, but at either side and +on the heaped-up edges of the foot-paths it still lay as white as +when it fell. The grey pavement had been cleaned and scraped, but +was still dangerously slippery, so that there were fewer +passengers than usual. Indeed, from the direction of the +Metropolitan Station no one was coming save the single gentleman +whose eccentric conduct had drawn my attention. + +He was a man of about fifty, tall, portly, and imposing, with a +massive, strongly marked face and a commanding figure. He was +dressed in a sombre yet rich style, in black frock-coat, shining +hat, neat brown gaiters, and well-cut pearl-grey trousers. Yet +his actions were in absurd contrast to the dignity of his dress +and features, for he was running hard, with occasional little +springs, such as a weary man gives who is little accustomed to +set any tax upon his legs. As he ran he jerked his hands up and +down, waggled his head, and writhed his face into the most +extraordinary contortions. + +"What on earth can be the matter with him?" I asked. "He is +looking up at the numbers of the houses." + +"I believe that he is coming here," said Holmes, rubbing his +hands. + +"Here?" + +"Yes; I rather think he is coming to consult me professionally. I +think that I recognise the symptoms. Ha! did I not tell you?" As +he spoke, the man, puffing and blowing, rushed at our door and +pulled at our bell until the whole house resounded with the +clanging. + +A few moments later he was in our room, still puffing, still +gesticulating, but with so fixed a look of grief and despair in +his eyes that our smiles were turned in an instant to horror and +pity. For a while he could not get his words out, but swayed his +body and plucked at his hair like one who has been driven to the +extreme limits of his reason. Then, suddenly springing to his +feet, he beat his head against the wall with such force that we +both rushed upon him and tore him away to the centre of the room. +Sherlock Holmes pushed him down into the easy-chair and, sitting +beside him, patted his hand and chatted with him in the easy, +soothing tones which he knew so well how to employ. + +"You have come to me to tell your story, have you not?" said he. +"You are fatigued with your haste. Pray wait until you have +recovered yourself, and then I shall be most happy to look into +any little problem which you may submit to me." + +The man sat for a minute or more with a heaving chest, fighting +against his emotion. Then he passed his handkerchief over his +brow, set his lips tight, and turned his face towards us. + +"No doubt you think me mad?" said he. + +"I see that you have had some great trouble," responded Holmes. + +"God knows I have!--a trouble which is enough to unseat my +reason, so sudden and so terrible is it. Public disgrace I might +have faced, although I am a man whose character has never yet +borne a stain. Private affliction also is the lot of every man; +but the two coming together, and in so frightful a form, have +been enough to shake my very soul. Besides, it is not I alone. +The very noblest in the land may suffer unless some way be found +out of this horrible affair." + +"Pray compose yourself, sir," said Holmes, "and let me have a +clear account of who you are and what it is that has befallen +you." + +"My name," answered our visitor, "is probably familiar to your +ears. I am Alexander Holder, of the banking firm of Holder & +Stevenson, of Threadneedle Street." + +The name was indeed well known to us as belonging to the senior +partner in the second largest private banking concern in the City +of London. What could have happened, then, to bring one of the +foremost citizens of London to this most pitiable pass? We +waited, all curiosity, until with another effort he braced +himself to tell his story. + +"I feel that time is of value," said he; "that is why I hastened +here when the police inspector suggested that I should secure +your co-operation. I came to Baker Street by the Underground and +hurried from there on foot, for the cabs go slowly through this +snow. That is why I was so out of breath, for I am a man who +takes very little exercise. I feel better now, and I will put the +facts before you as shortly and yet as clearly as I can. + +"It is, of course, well known to you that in a successful banking +business as much depends upon our being able to find remunerative +investments for our funds as upon our increasing our connection +and the number of our depositors. One of our most lucrative means +of laying out money is in the shape of loans, where the security +is unimpeachable. We have done a good deal in this direction +during the last few years, and there are many noble families to +whom we have advanced large sums upon the security of their +pictures, libraries, or plate. + +"Yesterday morning I was seated in my office at the bank when a +card was brought in to me by one of the clerks. I started when I +saw the name, for it was that of none other than--well, perhaps +even to you I had better say no more than that it was a name +which is a household word all over the earth--one of the highest, +noblest, most exalted names in England. I was overwhelmed by the +honour and attempted, when he entered, to say so, but he plunged +at once into business with the air of a man who wishes to hurry +quickly through a disagreeable task. + +"'Mr. Holder,' said he, 'I have been informed that you are in the +habit of advancing money.' + +"'The firm does so when the security is good.' I answered. + +"'It is absolutely essential to me,' said he, 'that I should have +50,000 pounds at once. I could, of course, borrow so trifling a +sum ten times over from my friends, but I much prefer to make it +a matter of business and to carry out that business myself. In my +position you can readily understand that it is unwise to place +one's self under obligations.' + +"'For how long, may I ask, do you want this sum?' I asked. + +"'Next Monday I have a large sum due to me, and I shall then most +certainly repay what you advance, with whatever interest you +think it right to charge. But it is very essential to me that the +money should be paid at once.' + +"'I should be happy to advance it without further parley from my +own private purse,' said I, 'were it not that the strain would be +rather more than it could bear. If, on the other hand, I am to do +it in the name of the firm, then in justice to my partner I must +insist that, even in your case, every businesslike precaution +should be taken.' + +"'I should much prefer to have it so,' said he, raising up a +square, black morocco case which he had laid beside his chair. +'You have doubtless heard of the Beryl Coronet?' + +"'One of the most precious public possessions of the empire,' +said I. + +"'Precisely.' He opened the case, and there, imbedded in soft, +flesh-coloured velvet, lay the magnificent piece of jewellery +which he had named. 'There are thirty-nine enormous beryls,' said +he, 'and the price of the gold chasing is incalculable. The +lowest estimate would put the worth of the coronet at double the +sum which I have asked. I am prepared to leave it with you as my +security.' + +"I took the precious case into my hands and looked in some +perplexity from it to my illustrious client. + +"'You doubt its value?' he asked. + +"'Not at all. I only doubt--' + +"'The propriety of my leaving it. You may set your mind at rest +about that. I should not dream of doing so were it not absolutely +certain that I should be able in four days to reclaim it. It is a +pure matter of form. Is the security sufficient?' + +"'Ample.' + +"'You understand, Mr. Holder, that I am giving you a strong proof +of the confidence which I have in you, founded upon all that I +have heard of you. I rely upon you not only to be discreet and to +refrain from all gossip upon the matter but, above all, to +preserve this coronet with every possible precaution because I +need not say that a great public scandal would be caused if any +harm were to befall it. Any injury to it would be almost as +serious as its complete loss, for there are no beryls in the +world to match these, and it would be impossible to replace them. +I leave it with you, however, with every confidence, and I shall +call for it in person on Monday morning.' + +"Seeing that my client was anxious to leave, I said no more but, +calling for my cashier, I ordered him to pay over fifty 1000 +pound notes. When I was alone once more, however, with the +precious case lying upon the table in front of me, I could not +but think with some misgivings of the immense responsibility +which it entailed upon me. There could be no doubt that, as it +was a national possession, a horrible scandal would ensue if any +misfortune should occur to it. I already regretted having ever +consented to take charge of it. However, it was too late to alter +the matter now, so I locked it up in my private safe and turned +once more to my work. + +"When evening came I felt that it would be an imprudence to leave +so precious a thing in the office behind me. Bankers' safes had +been forced before now, and why should not mine be? If so, how +terrible would be the position in which I should find myself! I +determined, therefore, that for the next few days I would always +carry the case backward and forward with me, so that it might +never be really out of my reach. With this intention, I called a +cab and drove out to my house at Streatham, carrying the jewel +with me. I did not breathe freely until I had taken it upstairs +and locked it in the bureau of my dressing-room. + +"And now a word as to my household, Mr. Holmes, for I wish you to +thoroughly understand the situation. My groom and my page sleep +out of the house, and may be set aside altogether. I have three +maid-servants who have been with me a number of years and whose +absolute reliability is quite above suspicion. Another, Lucy +Parr, the second waiting-maid, has only been in my service a few +months. She came with an excellent character, however, and has +always given me satisfaction. She is a very pretty girl and has +attracted admirers who have occasionally hung about the place. +That is the only drawback which we have found to her, but we +believe her to be a thoroughly good girl in every way. + +"So much for the servants. My family itself is so small that it +will not take me long to describe it. I am a widower and have an +only son, Arthur. He has been a disappointment to me, Mr. +Holmes--a grievous disappointment. I have no doubt that I am +myself to blame. People tell me that I have spoiled him. Very +likely I have. When my dear wife died I felt that he was all I +had to love. I could not bear to see the smile fade even for a +moment from his face. I have never denied him a wish. Perhaps it +would have been better for both of us had I been sterner, but I +meant it for the best. + +"It was naturally my intention that he should succeed me in my +business, but he was not of a business turn. He was wild, +wayward, and, to speak the truth, I could not trust him in the +handling of large sums of money. When he was young he became a +member of an aristocratic club, and there, having charming +manners, he was soon the intimate of a number of men with long +purses and expensive habits. He learned to play heavily at cards +and to squander money on the turf, until he had again and again +to come to me and implore me to give him an advance upon his +allowance, that he might settle his debts of honour. He tried +more than once to break away from the dangerous company which he +was keeping, but each time the influence of his friend, Sir +George Burnwell, was enough to draw him back again. + +"And, indeed, I could not wonder that such a man as Sir George +Burnwell should gain an influence over him, for he has frequently +brought him to my house, and I have found myself that I could +hardly resist the fascination of his manner. He is older than +Arthur, a man of the world to his finger-tips, one who had been +everywhere, seen everything, a brilliant talker, and a man of +great personal beauty. Yet when I think of him in cold blood, far +away from the glamour of his presence, I am convinced from his +cynical speech and the look which I have caught in his eyes that +he is one who should be deeply distrusted. So I think, and so, +too, thinks my little Mary, who has a woman's quick insight into +character. + +"And now there is only she to be described. She is my niece; but +when my brother died five years ago and left her alone in the +world I adopted her, and have looked upon her ever since as my +daughter. She is a sunbeam in my house--sweet, loving, beautiful, +a wonderful manager and housekeeper, yet as tender and quiet and +gentle as a woman could be. She is my right hand. I do not know +what I could do without her. In only one matter has she ever gone +against my wishes. Twice my boy has asked her to marry him, for +he loves her devotedly, but each time she has refused him. I +think that if anyone could have drawn him into the right path it +would have been she, and that his marriage might have changed his +whole life; but now, alas! it is too late--forever too late! + +"Now, Mr. Holmes, you know the people who live under my roof, and +I shall continue with my miserable story. + +"When we were taking coffee in the drawing-room that night after +dinner, I told Arthur and Mary my experience, and of the precious +treasure which we had under our roof, suppressing only the name +of my client. Lucy Parr, who had brought in the coffee, had, I am +sure, left the room; but I cannot swear that the door was closed. +Mary and Arthur were much interested and wished to see the famous +coronet, but I thought it better not to disturb it. + +"'Where have you put it?' asked Arthur. + +"'In my own bureau.' + +"'Well, I hope to goodness the house won't be burgled during the +night.' said he. + +"'It is locked up,' I answered. + +"'Oh, any old key will fit that bureau. When I was a youngster I +have opened it myself with the key of the box-room cupboard.' + +"He often had a wild way of talking, so that I thought little of +what he said. He followed me to my room, however, that night with +a very grave face. + +"'Look here, dad,' said he with his eyes cast down, 'can you let +me have 200 pounds?' + +"'No, I cannot!' I answered sharply. 'I have been far too +generous with you in money matters.' + +"'You have been very kind,' said he, 'but I must have this money, +or else I can never show my face inside the club again.' + +"'And a very good thing, too!' I cried. + +"'Yes, but you would not have me leave it a dishonoured man,' +said he. 'I could not bear the disgrace. I must raise the money +in some way, and if you will not let me have it, then I must try +other means.' + +"I was very angry, for this was the third demand during the +month. 'You shall not have a farthing from me,' I cried, on which +he bowed and left the room without another word. + +"When he was gone I unlocked my bureau, made sure that my +treasure was safe, and locked it again. Then I started to go +round the house to see that all was secure--a duty which I +usually leave to Mary but which I thought it well to perform +myself that night. As I came down the stairs I saw Mary herself +at the side window of the hall, which she closed and fastened as +I approached. + +"'Tell me, dad,' said she, looking, I thought, a little +disturbed, 'did you give Lucy, the maid, leave to go out +to-night?' + +"'Certainly not.' + +"'She came in just now by the back door. I have no doubt that she +has only been to the side gate to see someone, but I think that +it is hardly safe and should be stopped.' + +"'You must speak to her in the morning, or I will if you prefer +it. Are you sure that everything is fastened?' + +"'Quite sure, dad.' + +"'Then, good-night.' I kissed her and went up to my bedroom +again, where I was soon asleep. + +"I am endeavouring to tell you everything, Mr. Holmes, which may +have any bearing upon the case, but I beg that you will question +me upon any point which I do not make clear." + +"On the contrary, your statement is singularly lucid." + +"I come to a part of my story now in which I should wish to be +particularly so. I am not a very heavy sleeper, and the anxiety +in my mind tended, no doubt, to make me even less so than usual. +About two in the morning, then, I was awakened by some sound in +the house. It had ceased ere I was wide awake, but it had left an +impression behind it as though a window had gently closed +somewhere. I lay listening with all my ears. Suddenly, to my +horror, there was a distinct sound of footsteps moving softly in +the next room. I slipped out of bed, all palpitating with fear, +and peeped round the corner of my dressing-room door. + +"'Arthur!' I screamed, 'you villain! you thief! How dare you +touch that coronet?' + +"The gas was half up, as I had left it, and my unhappy boy, +dressed only in his shirt and trousers, was standing beside the +light, holding the coronet in his hands. He appeared to be +wrenching at it, or bending it with all his strength. At my cry +he dropped it from his grasp and turned as pale as death. I +snatched it up and examined it. One of the gold corners, with +three of the beryls in it, was missing. + +"'You blackguard!' I shouted, beside myself with rage. 'You have +destroyed it! You have dishonoured me forever! Where are the +jewels which you have stolen?' + +"'Stolen!' he cried. + +"'Yes, thief!' I roared, shaking him by the shoulder. + +"'There are none missing. There cannot be any missing,' said he. + +"'There are three missing. And you know where they are. Must I +call you a liar as well as a thief? Did I not see you trying to +tear off another piece?' + +"'You have called me names enough,' said he, 'I will not stand it +any longer. I shall not say another word about this business, +since you have chosen to insult me. I will leave your house in +the morning and make my own way in the world.' + +"'You shall leave it in the hands of the police!' I cried +half-mad with grief and rage. 'I shall have this matter probed to +the bottom.' + +"'You shall learn nothing from me,' said he with a passion such +as I should not have thought was in his nature. 'If you choose to +call the police, let the police find what they can.' + +"By this time the whole house was astir, for I had raised my +voice in my anger. Mary was the first to rush into my room, and, +at the sight of the coronet and of Arthur's face, she read the +whole story and, with a scream, fell down senseless on the +ground. I sent the house-maid for the police and put the +investigation into their hands at once. When the inspector and a +constable entered the house, Arthur, who had stood sullenly with +his arms folded, asked me whether it was my intention to charge +him with theft. I answered that it had ceased to be a private +matter, but had become a public one, since the ruined coronet was +national property. I was determined that the law should have its +way in everything. + +"'At least,' said he, 'you will not have me arrested at once. It +would be to your advantage as well as mine if I might leave the +house for five minutes.' + +"'That you may get away, or perhaps that you may conceal what you +have stolen,' said I. And then, realising the dreadful position +in which I was placed, I implored him to remember that not only +my honour but that of one who was far greater than I was at +stake; and that he threatened to raise a scandal which would +convulse the nation. He might avert it all if he would but tell +me what he had done with the three missing stones. + +"'You may as well face the matter,' said I; 'you have been caught +in the act, and no confession could make your guilt more heinous. +If you but make such reparation as is in your power, by telling +us where the beryls are, all shall be forgiven and forgotten.' + +"'Keep your forgiveness for those who ask for it,' he answered, +turning away from me with a sneer. I saw that he was too hardened +for any words of mine to influence him. There was but one way for +it. I called in the inspector and gave him into custody. A search +was made at once not only of his person but of his room and of +every portion of the house where he could possibly have concealed +the gems; but no trace of them could be found, nor would the +wretched boy open his mouth for all our persuasions and our +threats. This morning he was removed to a cell, and I, after +going through all the police formalities, have hurried round to +you to implore you to use your skill in unravelling the matter. +The police have openly confessed that they can at present make +nothing of it. You may go to any expense which you think +necessary. I have already offered a reward of 1000 pounds. My +God, what shall I do! I have lost my honour, my gems, and my son +in one night. Oh, what shall I do!" + +He put a hand on either side of his head and rocked himself to +and fro, droning to himself like a child whose grief has got +beyond words. + +Sherlock Holmes sat silent for some few minutes, with his brows +knitted and his eyes fixed upon the fire. + +"Do you receive much company?" he asked. + +"None save my partner with his family and an occasional friend of +Arthur's. Sir George Burnwell has been several times lately. No +one else, I think." + +"Do you go out much in society?" + +"Arthur does. Mary and I stay at home. We neither of us care for +it." + +"That is unusual in a young girl." + +"She is of a quiet nature. Besides, she is not so very young. She +is four-and-twenty." + +"This matter, from what you say, seems to have been a shock to +her also." + +"Terrible! She is even more affected than I." + +"You have neither of you any doubt as to your son's guilt?" + +"How can we have when I saw him with my own eyes with the coronet +in his hands." + +"I hardly consider that a conclusive proof. Was the remainder of +the coronet at all injured?" + +"Yes, it was twisted." + +"Do you not think, then, that he might have been trying to +straighten it?" + +"God bless you! You are doing what you can for him and for me. +But it is too heavy a task. What was he doing there at all? If +his purpose were innocent, why did he not say so?" + +"Precisely. And if it were guilty, why did he not invent a lie? +His silence appears to me to cut both ways. There are several +singular points about the case. What did the police think of the +noise which awoke you from your sleep?" + +"They considered that it might be caused by Arthur's closing his +bedroom door." + +"A likely story! As if a man bent on felony would slam his door +so as to wake a household. What did they say, then, of the +disappearance of these gems?" + +"They are still sounding the planking and probing the furniture +in the hope of finding them." + +"Have they thought of looking outside the house?" + +"Yes, they have shown extraordinary energy. The whole garden has +already been minutely examined." + +"Now, my dear sir," said Holmes, "is it not obvious to you now +that this matter really strikes very much deeper than either you +or the police were at first inclined to think? It appeared to you +to be a simple case; to me it seems exceedingly complex. Consider +what is involved by your theory. You suppose that your son came +down from his bed, went, at great risk, to your dressing-room, +opened your bureau, took out your coronet, broke off by main +force a small portion of it, went off to some other place, +concealed three gems out of the thirty-nine, with such skill that +nobody can find them, and then returned with the other thirty-six +into the room in which he exposed himself to the greatest danger +of being discovered. I ask you now, is such a theory tenable?" + +"But what other is there?" cried the banker with a gesture of +despair. "If his motives were innocent, why does he not explain +them?" + +"It is our task to find that out," replied Holmes; "so now, if +you please, Mr. Holder, we will set off for Streatham together, +and devote an hour to glancing a little more closely into +details." + +My friend insisted upon my accompanying them in their expedition, +which I was eager enough to do, for my curiosity and sympathy +were deeply stirred by the story to which we had listened. I +confess that the guilt of the banker's son appeared to me to be +as obvious as it did to his unhappy father, but still I had such +faith in Holmes' judgment that I felt that there must be some +grounds for hope as long as he was dissatisfied with the accepted +explanation. He hardly spoke a word the whole way out to the +southern suburb, but sat with his chin upon his breast and his +hat drawn over his eyes, sunk in the deepest thought. Our client +appeared to have taken fresh heart at the little glimpse of hope +which had been presented to him, and he even broke into a +desultory chat with me over his business affairs. A short railway +journey and a shorter walk brought us to Fairbank, the modest +residence of the great financier. + +Fairbank was a good-sized square house of white stone, standing +back a little from the road. A double carriage-sweep, with a +snow-clad lawn, stretched down in front to two large iron gates +which closed the entrance. On the right side was a small wooden +thicket, which led into a narrow path between two neat hedges +stretching from the road to the kitchen door, and forming the +tradesmen's entrance. On the left ran a lane which led to the +stables, and was not itself within the grounds at all, being a +public, though little used, thoroughfare. Holmes left us standing +at the door and walked slowly all round the house, across the +front, down the tradesmen's path, and so round by the garden +behind into the stable lane. So long was he that Mr. Holder and I +went into the dining-room and waited by the fire until he should +return. We were sitting there in silence when the door opened and +a young lady came in. She was rather above the middle height, +slim, with dark hair and eyes, which seemed the darker against +the absolute pallor of her skin. I do not think that I have ever +seen such deadly paleness in a woman's face. Her lips, too, were +bloodless, but her eyes were flushed with crying. As she swept +silently into the room she impressed me with a greater sense of +grief than the banker had done in the morning, and it was the +more striking in her as she was evidently a woman of strong +character, with immense capacity for self-restraint. Disregarding +my presence, she went straight to her uncle and passed her hand +over his head with a sweet womanly caress. + +"You have given orders that Arthur should be liberated, have you +not, dad?" she asked. + +"No, no, my girl, the matter must be probed to the bottom." + +"But I am so sure that he is innocent. You know what woman's +instincts are. I know that he has done no harm and that you will +be sorry for having acted so harshly." + +"Why is he silent, then, if he is innocent?" + +"Who knows? Perhaps because he was so angry that you should +suspect him." + +"How could I help suspecting him, when I actually saw him with +the coronet in his hand?" + +"Oh, but he had only picked it up to look at it. Oh, do, do take +my word for it that he is innocent. Let the matter drop and say +no more. It is so dreadful to think of our dear Arthur in +prison!" + +"I shall never let it drop until the gems are found--never, Mary! +Your affection for Arthur blinds you as to the awful consequences +to me. Far from hushing the thing up, I have brought a gentleman +down from London to inquire more deeply into it." + +"This gentleman?" she asked, facing round to me. + +"No, his friend. He wished us to leave him alone. He is round in +the stable lane now." + +"The stable lane?" She raised her dark eyebrows. "What can he +hope to find there? Ah! this, I suppose, is he. I trust, sir, +that you will succeed in proving, what I feel sure is the truth, +that my cousin Arthur is innocent of this crime." + +"I fully share your opinion, and I trust, with you, that we may +prove it," returned Holmes, going back to the mat to knock the +snow from his shoes. "I believe I have the honour of addressing +Miss Mary Holder. Might I ask you a question or two?" + +"Pray do, sir, if it may help to clear this horrible affair up." + +"You heard nothing yourself last night?" + +"Nothing, until my uncle here began to speak loudly. I heard +that, and I came down." + +"You shut up the windows and doors the night before. Did you +fasten all the windows?" + +"Yes." + +"Were they all fastened this morning?" + +"Yes." + +"You have a maid who has a sweetheart? I think that you remarked +to your uncle last night that she had been out to see him?" + +"Yes, and she was the girl who waited in the drawing-room, and +who may have heard uncle's remarks about the coronet." + +"I see. You infer that she may have gone out to tell her +sweetheart, and that the two may have planned the robbery." + +"But what is the good of all these vague theories," cried the +banker impatiently, "when I have told you that I saw Arthur with +the coronet in his hands?" + +"Wait a little, Mr. Holder. We must come back to that. About this +girl, Miss Holder. You saw her return by the kitchen door, I +presume?" + +"Yes; when I went to see if the door was fastened for the night I +met her slipping in. I saw the man, too, in the gloom." + +"Do you know him?" + +"Oh, yes! he is the green-grocer who brings our vegetables round. +His name is Francis Prosper." + +"He stood," said Holmes, "to the left of the door--that is to +say, farther up the path than is necessary to reach the door?" + +"Yes, he did." + +"And he is a man with a wooden leg?" + +Something like fear sprang up in the young lady's expressive +black eyes. "Why, you are like a magician," said she. "How do you +know that?" She smiled, but there was no answering smile in +Holmes' thin, eager face. + +"I should be very glad now to go upstairs," said he. "I shall +probably wish to go over the outside of the house again. Perhaps +I had better take a look at the lower windows before I go up." + +He walked swiftly round from one to the other, pausing only at +the large one which looked from the hall onto the stable lane. +This he opened and made a very careful examination of the sill +with his powerful magnifying lens. "Now we shall go upstairs," +said he at last. + +The banker's dressing-room was a plainly furnished little +chamber, with a grey carpet, a large bureau, and a long mirror. +Holmes went to the bureau first and looked hard at the lock. + +"Which key was used to open it?" he asked. + +"That which my son himself indicated--that of the cupboard of the +lumber-room." + +"Have you it here?" + +"That is it on the dressing-table." + +Sherlock Holmes took it up and opened the bureau. + +"It is a noiseless lock," said he. "It is no wonder that it did +not wake you. This case, I presume, contains the coronet. We must +have a look at it." He opened the case, and taking out the diadem +he laid it upon the table. It was a magnificent specimen of the +jeweller's art, and the thirty-six stones were the finest that I +have ever seen. At one side of the coronet was a cracked edge, +where a corner holding three gems had been torn away. + +"Now, Mr. Holder," said Holmes, "here is the corner which +corresponds to that which has been so unfortunately lost. Might I +beg that you will break it off." + +The banker recoiled in horror. "I should not dream of trying," +said he. + +"Then I will." Holmes suddenly bent his strength upon it, but +without result. "I feel it give a little," said he; "but, though +I am exceptionally strong in the fingers, it would take me all my +time to break it. An ordinary man could not do it. Now, what do +you think would happen if I did break it, Mr. Holder? There would +be a noise like a pistol shot. Do you tell me that all this +happened within a few yards of your bed and that you heard +nothing of it?" + +"I do not know what to think. It is all dark to me." + +"But perhaps it may grow lighter as we go. What do you think, +Miss Holder?" + +"I confess that I still share my uncle's perplexity." + +"Your son had no shoes or slippers on when you saw him?" + +"He had nothing on save only his trousers and shirt." + +"Thank you. We have certainly been favoured with extraordinary +luck during this inquiry, and it will be entirely our own fault +if we do not succeed in clearing the matter up. With your +permission, Mr. Holder, I shall now continue my investigations +outside." + +He went alone, at his own request, for he explained that any +unnecessary footmarks might make his task more difficult. For an +hour or more he was at work, returning at last with his feet +heavy with snow and his features as inscrutable as ever. + +"I think that I have seen now all that there is to see, Mr. +Holder," said he; "I can serve you best by returning to my +rooms." + +"But the gems, Mr. Holmes. Where are they?" + +"I cannot tell." + +The banker wrung his hands. "I shall never see them again!" he +cried. "And my son? You give me hopes?" + +"My opinion is in no way altered." + +"Then, for God's sake, what was this dark business which was +acted in my house last night?" + +"If you can call upon me at my Baker Street rooms to-morrow +morning between nine and ten I shall be happy to do what I can to +make it clearer. I understand that you give me carte blanche to +act for you, provided only that I get back the gems, and that you +place no limit on the sum I may draw." + +"I would give my fortune to have them back." + +"Very good. I shall look into the matter between this and then. +Good-bye; it is just possible that I may have to come over here +again before evening." + +It was obvious to me that my companion's mind was now made up +about the case, although what his conclusions were was more than +I could even dimly imagine. Several times during our homeward +journey I endeavoured to sound him upon the point, but he always +glided away to some other topic, until at last I gave it over in +despair. It was not yet three when we found ourselves in our +rooms once more. He hurried to his chamber and was down again in +a few minutes dressed as a common loafer. With his collar turned +up, his shiny, seedy coat, his red cravat, and his worn boots, he +was a perfect sample of the class. + +"I think that this should do," said he, glancing into the glass +above the fireplace. "I only wish that you could come with me, +Watson, but I fear that it won't do. I may be on the trail in +this matter, or I may be following a will-o'-the-wisp, but I +shall soon know which it is. I hope that I may be back in a few +hours." He cut a slice of beef from the joint upon the sideboard, +sandwiched it between two rounds of bread, and thrusting this +rude meal into his pocket he started off upon his expedition. + +I had just finished my tea when he returned, evidently in +excellent spirits, swinging an old elastic-sided boot in his +hand. He chucked it down into a corner and helped himself to a +cup of tea. + +"I only looked in as I passed," said he. "I am going right on." + +"Where to?" + +"Oh, to the other side of the West End. It may be some time +before I get back. Don't wait up for me in case I should be +late." + +"How are you getting on?" + +"Oh, so so. Nothing to complain of. I have been out to Streatham +since I saw you last, but I did not call at the house. It is a +very sweet little problem, and I would not have missed it for a +good deal. However, I must not sit gossiping here, but must get +these disreputable clothes off and return to my highly +respectable self." + +I could see by his manner that he had stronger reasons for +satisfaction than his words alone would imply. His eyes twinkled, +and there was even a touch of colour upon his sallow cheeks. He +hastened upstairs, and a few minutes later I heard the slam of +the hall door, which told me that he was off once more upon his +congenial hunt. + +I waited until midnight, but there was no sign of his return, so +I retired to my room. It was no uncommon thing for him to be away +for days and nights on end when he was hot upon a scent, so that +his lateness caused me no surprise. I do not know at what hour he +came in, but when I came down to breakfast in the morning there +he was with a cup of coffee in one hand and the paper in the +other, as fresh and trim as possible. + +"You will excuse my beginning without you, Watson," said he, "but +you remember that our client has rather an early appointment this +morning." + +"Why, it is after nine now," I answered. "I should not be +surprised if that were he. I thought I heard a ring." + +It was, indeed, our friend the financier. I was shocked by the +change which had come over him, for his face which was naturally +of a broad and massive mould, was now pinched and fallen in, +while his hair seemed to me at least a shade whiter. He entered +with a weariness and lethargy which was even more painful than +his violence of the morning before, and he dropped heavily into +the armchair which I pushed forward for him. + +"I do not know what I have done to be so severely tried," said +he. "Only two days ago I was a happy and prosperous man, without +a care in the world. Now I am left to a lonely and dishonoured +age. One sorrow comes close upon the heels of another. My niece, +Mary, has deserted me." + +"Deserted you?" + +"Yes. Her bed this morning had not been slept in, her room was +empty, and a note for me lay upon the hall table. I had said to +her last night, in sorrow and not in anger, that if she had +married my boy all might have been well with him. Perhaps it was +thoughtless of me to say so. It is to that remark that she refers +in this note: + +"'MY DEAREST UNCLE:--I feel that I have brought trouble upon you, +and that if I had acted differently this terrible misfortune +might never have occurred. I cannot, with this thought in my +mind, ever again be happy under your roof, and I feel that I must +leave you forever. Do not worry about my future, for that is +provided for; and, above all, do not search for me, for it will +be fruitless labour and an ill-service to me. In life or in +death, I am ever your loving,--MARY.' + +"What could she mean by that note, Mr. Holmes? Do you think it +points to suicide?" + +"No, no, nothing of the kind. It is perhaps the best possible +solution. I trust, Mr. Holder, that you are nearing the end of +your troubles." + +"Ha! You say so! You have heard something, Mr. Holmes; you have +learned something! Where are the gems?" + +"You would not think 1000 pounds apiece an excessive sum for +them?" + +"I would pay ten." + +"That would be unnecessary. Three thousand will cover the matter. +And there is a little reward, I fancy. Have you your check-book? +Here is a pen. Better make it out for 4000 pounds." + +With a dazed face the banker made out the required check. Holmes +walked over to his desk, took out a little triangular piece of +gold with three gems in it, and threw it down upon the table. + +With a shriek of joy our client clutched it up. + +"You have it!" he gasped. "I am saved! I am saved!" + +The reaction of joy was as passionate as his grief had been, and +he hugged his recovered gems to his bosom. + +"There is one other thing you owe, Mr. Holder," said Sherlock +Holmes rather sternly. + +"Owe!" He caught up a pen. "Name the sum, and I will pay it." + +"No, the debt is not to me. You owe a very humble apology to that +noble lad, your son, who has carried himself in this matter as I +should be proud to see my own son do, should I ever chance to +have one." + +"Then it was not Arthur who took them?" + +"I told you yesterday, and I repeat to-day, that it was not." + +"You are sure of it! Then let us hurry to him at once to let him +know that the truth is known." + +"He knows it already. When I had cleared it all up I had an +interview with him, and finding that he would not tell me the +story, I told it to him, on which he had to confess that I was +right and to add the very few details which were not yet quite +clear to me. Your news of this morning, however, may open his +lips." + +"For heaven's sake, tell me, then, what is this extraordinary +mystery!" + +"I will do so, and I will show you the steps by which I reached +it. And let me say to you, first, that which it is hardest for me +to say and for you to hear: there has been an understanding +between Sir George Burnwell and your niece Mary. They have now +fled together." + +"My Mary? Impossible!" + +"It is unfortunately more than possible; it is certain. Neither +you nor your son knew the true character of this man when you +admitted him into your family circle. He is one of the most +dangerous men in England--a ruined gambler, an absolutely +desperate villain, a man without heart or conscience. Your niece +knew nothing of such men. When he breathed his vows to her, as he +had done to a hundred before her, she flattered herself that she +alone had touched his heart. The devil knows best what he said, +but at least she became his tool and was in the habit of seeing +him nearly every evening." + +"I cannot, and I will not, believe it!" cried the banker with an +ashen face. + +"I will tell you, then, what occurred in your house last night. +Your niece, when you had, as she thought, gone to your room, +slipped down and talked to her lover through the window which +leads into the stable lane. His footmarks had pressed right +through the snow, so long had he stood there. She told him of the +coronet. His wicked lust for gold kindled at the news, and he +bent her to his will. I have no doubt that she loved you, but +there are women in whom the love of a lover extinguishes all +other loves, and I think that she must have been one. She had +hardly listened to his instructions when she saw you coming +downstairs, on which she closed the window rapidly and told you +about one of the servants' escapade with her wooden-legged lover, +which was all perfectly true. + +"Your boy, Arthur, went to bed after his interview with you but +he slept badly on account of his uneasiness about his club debts. +In the middle of the night he heard a soft tread pass his door, +so he rose and, looking out, was surprised to see his cousin +walking very stealthily along the passage until she disappeared +into your dressing-room. Petrified with astonishment, the lad +slipped on some clothes and waited there in the dark to see what +would come of this strange affair. Presently she emerged from the +room again, and in the light of the passage-lamp your son saw +that she carried the precious coronet in her hands. She passed +down the stairs, and he, thrilling with horror, ran along and +slipped behind the curtain near your door, whence he could see +what passed in the hall beneath. He saw her stealthily open the +window, hand out the coronet to someone in the gloom, and then +closing it once more hurry back to her room, passing quite close +to where he stood hid behind the curtain. + +"As long as she was on the scene he could not take any action +without a horrible exposure of the woman whom he loved. But the +instant that she was gone he realised how crushing a misfortune +this would be for you, and how all-important it was to set it +right. He rushed down, just as he was, in his bare feet, opened +the window, sprang out into the snow, and ran down the lane, +where he could see a dark figure in the moonlight. Sir George +Burnwell tried to get away, but Arthur caught him, and there was +a struggle between them, your lad tugging at one side of the +coronet, and his opponent at the other. In the scuffle, your son +struck Sir George and cut him over the eye. Then something +suddenly snapped, and your son, finding that he had the coronet +in his hands, rushed back, closed the window, ascended to your +room, and had just observed that the coronet had been twisted in +the struggle and was endeavouring to straighten it when you +appeared upon the scene." + +"Is it possible?" gasped the banker. + +"You then roused his anger by calling him names at a moment when +he felt that he had deserved your warmest thanks. He could not +explain the true state of affairs without betraying one who +certainly deserved little enough consideration at his hands. He +took the more chivalrous view, however, and preserved her +secret." + +"And that was why she shrieked and fainted when she saw the +coronet," cried Mr. Holder. "Oh, my God! what a blind fool I have +been! And his asking to be allowed to go out for five minutes! +The dear fellow wanted to see if the missing piece were at the +scene of the struggle. How cruelly I have misjudged him!" + +"When I arrived at the house," continued Holmes, "I at once went +very carefully round it to observe if there were any traces in +the snow which might help me. I knew that none had fallen since +the evening before, and also that there had been a strong frost +to preserve impressions. I passed along the tradesmen's path, but +found it all trampled down and indistinguishable. Just beyond it, +however, at the far side of the kitchen door, a woman had stood +and talked with a man, whose round impressions on one side showed +that he had a wooden leg. I could even tell that they had been +disturbed, for the woman had run back swiftly to the door, as was +shown by the deep toe and light heel marks, while Wooden-leg had +waited a little, and then had gone away. I thought at the time +that this might be the maid and her sweetheart, of whom you had +already spoken to me, and inquiry showed it was so. I passed +round the garden without seeing anything more than random tracks, +which I took to be the police; but when I got into the stable +lane a very long and complex story was written in the snow in +front of me. + +"There was a double line of tracks of a booted man, and a second +double line which I saw with delight belonged to a man with naked +feet. I was at once convinced from what you had told me that the +latter was your son. The first had walked both ways, but the +other had run swiftly, and as his tread was marked in places over +the depression of the boot, it was obvious that he had passed +after the other. I followed them up and found they led to the +hall window, where Boots had worn all the snow away while +waiting. Then I walked to the other end, which was a hundred +yards or more down the lane. I saw where Boots had faced round, +where the snow was cut up as though there had been a struggle, +and, finally, where a few drops of blood had fallen, to show me +that I was not mistaken. Boots had then run down the lane, and +another little smudge of blood showed that it was he who had been +hurt. When he came to the highroad at the other end, I found that +the pavement had been cleared, so there was an end to that clue. + +"On entering the house, however, I examined, as you remember, the +sill and framework of the hall window with my lens, and I could +at once see that someone had passed out. I could distinguish the +outline of an instep where the wet foot had been placed in coming +in. I was then beginning to be able to form an opinion as to what +had occurred. A man had waited outside the window; someone had +brought the gems; the deed had been overseen by your son; he had +pursued the thief; had struggled with him; they had each tugged +at the coronet, their united strength causing injuries which +neither alone could have effected. He had returned with the +prize, but had left a fragment in the grasp of his opponent. So +far I was clear. The question now was, who was the man and who +was it brought him the coronet? + +"It is an old maxim of mine that when you have excluded the +impossible, whatever remains, however improbable, must be the +truth. Now, I knew that it was not you who had brought it down, +so there only remained your niece and the maids. But if it were +the maids, why should your son allow himself to be accused in +their place? There could be no possible reason. As he loved his +cousin, however, there was an excellent explanation why he should +retain her secret--the more so as the secret was a disgraceful +one. When I remembered that you had seen her at that window, and +how she had fainted on seeing the coronet again, my conjecture +became a certainty. + +"And who could it be who was her confederate? A lover evidently, +for who else could outweigh the love and gratitude which she must +feel to you? I knew that you went out little, and that your +circle of friends was a very limited one. But among them was Sir +George Burnwell. I had heard of him before as being a man of evil +reputation among women. It must have been he who wore those boots +and retained the missing gems. Even though he knew that Arthur +had discovered him, he might still flatter himself that he was +safe, for the lad could not say a word without compromising his +own family. + +"Well, your own good sense will suggest what measures I took +next. I went in the shape of a loafer to Sir George's house, +managed to pick up an acquaintance with his valet, learned that +his master had cut his head the night before, and, finally, at +the expense of six shillings, made all sure by buying a pair of +his cast-off shoes. With these I journeyed down to Streatham and +saw that they exactly fitted the tracks." + +"I saw an ill-dressed vagabond in the lane yesterday evening," +said Mr. Holder. + +"Precisely. It was I. I found that I had my man, so I came home +and changed my clothes. It was a delicate part which I had to +play then, for I saw that a prosecution must be avoided to avert +scandal, and I knew that so astute a villain would see that our +hands were tied in the matter. I went and saw him. At first, of +course, he denied everything. But when I gave him every +particular that had occurred, he tried to bluster and took down a +life-preserver from the wall. I knew my man, however, and I +clapped a pistol to his head before he could strike. Then he +became a little more reasonable. I told him that we would give +him a price for the stones he held--1000 pounds apiece. That +brought out the first signs of grief that he had shown. 'Why, +dash it all!' said he, 'I've let them go at six hundred for the +three!' I soon managed to get the address of the receiver who had +them, on promising him that there would be no prosecution. Off I +set to him, and after much chaffering I got our stones at 1000 +pounds apiece. Then I looked in upon your son, told him that all +was right, and eventually got to my bed about two o'clock, after +what I may call a really hard day's work." + +"A day which has saved England from a great public scandal," said +the banker, rising. "Sir, I cannot find words to thank you, but +you shall not find me ungrateful for what you have done. Your +skill has indeed exceeded all that I have heard of it. And now I +must fly to my dear boy to apologise to him for the wrong which I +have done him. As to what you tell me of poor Mary, it goes to my +very heart. Not even your skill can inform me where she is now." + +"I think that we may safely say," returned Holmes, "that she is +wherever Sir George Burnwell is. It is equally certain, too, that +whatever her sins are, they will soon receive a more than +sufficient punishment." + + + +XII. THE ADVENTURE OF THE COPPER BEECHES + +"To the man who loves art for its own sake," remarked Sherlock +Holmes, tossing aside the advertisement sheet of the Daily +Telegraph, "it is frequently in its least important and lowliest +manifestations that the keenest pleasure is to be derived. It is +pleasant to me to observe, Watson, that you have so far grasped +this truth that in these little records of our cases which you +have been good enough to draw up, and, I am bound to say, +occasionally to embellish, you have given prominence not so much +to the many causes célèbres and sensational trials in which I +have figured but rather to those incidents which may have been +trivial in themselves, but which have given room for those +faculties of deduction and of logical synthesis which I have made +my special province." + +"And yet," said I, smiling, "I cannot quite hold myself absolved +from the charge of sensationalism which has been urged against my +records." + +"You have erred, perhaps," he observed, taking up a glowing +cinder with the tongs and lighting with it the long cherry-wood +pipe which was wont to replace his clay when he was in a +disputatious rather than a meditative mood--"you have erred +perhaps in attempting to put colour and life into each of your +statements instead of confining yourself to the task of placing +upon record that severe reasoning from cause to effect which is +really the only notable feature about the thing." + +"It seems to me that I have done you full justice in the matter," +I remarked with some coldness, for I was repelled by the egotism +which I had more than once observed to be a strong factor in my +friend's singular character. + +"No, it is not selfishness or conceit," said he, answering, as +was his wont, my thoughts rather than my words. "If I claim full +justice for my art, it is because it is an impersonal thing--a +thing beyond myself. Crime is common. Logic is rare. Therefore it +is upon the logic rather than upon the crime that you should +dwell. You have degraded what should have been a course of +lectures into a series of tales." + +It was a cold morning of the early spring, and we sat after +breakfast on either side of a cheery fire in the old room at +Baker Street. A thick fog rolled down between the lines of +dun-coloured houses, and the opposing windows loomed like dark, +shapeless blurs through the heavy yellow wreaths. Our gas was lit +and shone on the white cloth and glimmer of china and metal, for +the table had not been cleared yet. Sherlock Holmes had been +silent all the morning, dipping continuously into the +advertisement columns of a succession of papers until at last, +having apparently given up his search, he had emerged in no very +sweet temper to lecture me upon my literary shortcomings. + +"At the same time," he remarked after a pause, during which he +had sat puffing at his long pipe and gazing down into the fire, +"you can hardly be open to a charge of sensationalism, for out of +these cases which you have been so kind as to interest yourself +in, a fair proportion do not treat of crime, in its legal sense, +at all. The small matter in which I endeavoured to help the King +of Bohemia, the singular experience of Miss Mary Sutherland, the +problem connected with the man with the twisted lip, and the +incident of the noble bachelor, were all matters which are +outside the pale of the law. But in avoiding the sensational, I +fear that you may have bordered on the trivial." + +"The end may have been so," I answered, "but the methods I hold +to have been novel and of interest." + +"Pshaw, my dear fellow, what do the public, the great unobservant +public, who could hardly tell a weaver by his tooth or a +compositor by his left thumb, care about the finer shades of +analysis and deduction! But, indeed, if you are trivial, I cannot +blame you, for the days of the great cases are past. Man, or at +least criminal man, has lost all enterprise and originality. As +to my own little practice, it seems to be degenerating into an +agency for recovering lost lead pencils and giving advice to +young ladies from boarding-schools. I think that I have touched +bottom at last, however. This note I had this morning marks my +zero-point, I fancy. Read it!" He tossed a crumpled letter across +to me. + +It was dated from Montague Place upon the preceding evening, and +ran thus: + +"DEAR MR. HOLMES:--I am very anxious to consult you as to whether +I should or should not accept a situation which has been offered +to me as governess. I shall call at half-past ten to-morrow if I +do not inconvenience you. Yours faithfully, + "VIOLET HUNTER." + +"Do you know the young lady?" I asked. + +"Not I." + +"It is half-past ten now." + +"Yes, and I have no doubt that is her ring." + +"It may turn out to be of more interest than you think. You +remember that the affair of the blue carbuncle, which appeared to +be a mere whim at first, developed into a serious investigation. +It may be so in this case, also." + +"Well, let us hope so. But our doubts will very soon be solved, +for here, unless I am much mistaken, is the person in question." + +As he spoke the door opened and a young lady entered the room. +She was plainly but neatly dressed, with a bright, quick face, +freckled like a plover's egg, and with the brisk manner of a +woman who has had her own way to make in the world. + +"You will excuse my troubling you, I am sure," said she, as my +companion rose to greet her, "but I have had a very strange +experience, and as I have no parents or relations of any sort +from whom I could ask advice, I thought that perhaps you would be +kind enough to tell me what I should do." + +"Pray take a seat, Miss Hunter. I shall be happy to do anything +that I can to serve you." + +I could see that Holmes was favourably impressed by the manner +and speech of his new client. He looked her over in his searching +fashion, and then composed himself, with his lids drooping and +his finger-tips together, to listen to her story. + +"I have been a governess for five years," said she, "in the +family of Colonel Spence Munro, but two months ago the colonel +received an appointment at Halifax, in Nova Scotia, and took his +children over to America with him, so that I found myself without +a situation. I advertised, and I answered advertisements, but +without success. At last the little money which I had saved began +to run short, and I was at my wit's end as to what I should do. + +"There is a well-known agency for governesses in the West End +called Westaway's, and there I used to call about once a week in +order to see whether anything had turned up which might suit me. +Westaway was the name of the founder of the business, but it is +really managed by Miss Stoper. She sits in her own little office, +and the ladies who are seeking employment wait in an anteroom, +and are then shown in one by one, when she consults her ledgers +and sees whether she has anything which would suit them. + +"Well, when I called last week I was shown into the little office +as usual, but I found that Miss Stoper was not alone. A +prodigiously stout man with a very smiling face and a great heavy +chin which rolled down in fold upon fold over his throat sat at +her elbow with a pair of glasses on his nose, looking very +earnestly at the ladies who entered. As I came in he gave quite a +jump in his chair and turned quickly to Miss Stoper. + +"'That will do,' said he; 'I could not ask for anything better. +Capital! capital!' He seemed quite enthusiastic and rubbed his +hands together in the most genial fashion. He was such a +comfortable-looking man that it was quite a pleasure to look at +him. + +"'You are looking for a situation, miss?' he asked. + +"'Yes, sir.' + +"'As governess?' + +"'Yes, sir.' + +"'And what salary do you ask?' + +"'I had 4 pounds a month in my last place with Colonel Spence +Munro.' + +"'Oh, tut, tut! sweating--rank sweating!' he cried, throwing his +fat hands out into the air like a man who is in a boiling +passion. 'How could anyone offer so pitiful a sum to a lady with +such attractions and accomplishments?' + +"'My accomplishments, sir, may be less than you imagine,' said I. +'A little French, a little German, music, and drawing--' + +"'Tut, tut!' he cried. 'This is all quite beside the question. +The point is, have you or have you not the bearing and deportment +of a lady? There it is in a nutshell. If you have not, you are +not fitted for the rearing of a child who may some day play a +considerable part in the history of the country. But if you have +why, then, how could any gentleman ask you to condescend to +accept anything under the three figures? Your salary with me, +madam, would commence at 100 pounds a year.' + +"You may imagine, Mr. Holmes, that to me, destitute as I was, +such an offer seemed almost too good to be true. The gentleman, +however, seeing perhaps the look of incredulity upon my face, +opened a pocket-book and took out a note. + +"'It is also my custom,' said he, smiling in the most pleasant +fashion until his eyes were just two little shining slits amid +the white creases of his face, 'to advance to my young ladies +half their salary beforehand, so that they may meet any little +expenses of their journey and their wardrobe.' + +"It seemed to me that I had never met so fascinating and so +thoughtful a man. As I was already in debt to my tradesmen, the +advance was a great convenience, and yet there was something +unnatural about the whole transaction which made me wish to know +a little more before I quite committed myself. + +"'May I ask where you live, sir?' said I. + +"'Hampshire. Charming rural place. The Copper Beeches, five miles +on the far side of Winchester. It is the most lovely country, my +dear young lady, and the dearest old country-house.' + +"'And my duties, sir? I should be glad to know what they would +be.' + +"'One child--one dear little romper just six years old. Oh, if +you could see him killing cockroaches with a slipper! Smack! +smack! smack! Three gone before you could wink!' He leaned back +in his chair and laughed his eyes into his head again. + +"I was a little startled at the nature of the child's amusement, +but the father's laughter made me think that perhaps he was +joking. + +"'My sole duties, then,' I asked, 'are to take charge of a single +child?' + +"'No, no, not the sole, not the sole, my dear young lady,' he +cried. 'Your duty would be, as I am sure your good sense would +suggest, to obey any little commands my wife might give, provided +always that they were such commands as a lady might with +propriety obey. You see no difficulty, heh?' + +"'I should be happy to make myself useful.' + +"'Quite so. In dress now, for example. We are faddy people, you +know--faddy but kind-hearted. If you were asked to wear any dress +which we might give you, you would not object to our little whim. +Heh?' + +"'No,' said I, considerably astonished at his words. + +"'Or to sit here, or sit there, that would not be offensive to +you?' + +"'Oh, no.' + +"'Or to cut your hair quite short before you come to us?' + +"I could hardly believe my ears. As you may observe, Mr. Holmes, +my hair is somewhat luxuriant, and of a rather peculiar tint of +chestnut. It has been considered artistic. I could not dream of +sacrificing it in this offhand fashion. + +"'I am afraid that that is quite impossible,' said I. He had been +watching me eagerly out of his small eyes, and I could see a +shadow pass over his face as I spoke. + +"'I am afraid that it is quite essential,' said he. 'It is a +little fancy of my wife's, and ladies' fancies, you know, madam, +ladies' fancies must be consulted. And so you won't cut your +hair?' + +"'No, sir, I really could not,' I answered firmly. + +"'Ah, very well; then that quite settles the matter. It is a +pity, because in other respects you would really have done very +nicely. In that case, Miss Stoper, I had best inspect a few more +of your young ladies.' + +"The manageress had sat all this while busy with her papers +without a word to either of us, but she glanced at me now with so +much annoyance upon her face that I could not help suspecting +that she had lost a handsome commission through my refusal. + +"'Do you desire your name to be kept upon the books?' she asked. + +"'If you please, Miss Stoper.' + +"'Well, really, it seems rather useless, since you refuse the +most excellent offers in this fashion,' said she sharply. 'You +can hardly expect us to exert ourselves to find another such +opening for you. Good-day to you, Miss Hunter.' She struck a gong +upon the table, and I was shown out by the page. + +"Well, Mr. Holmes, when I got back to my lodgings and found +little enough in the cupboard, and two or three bills upon the +table, I began to ask myself whether I had not done a very +foolish thing. After all, if these people had strange fads and +expected obedience on the most extraordinary matters, they were +at least ready to pay for their eccentricity. Very few +governesses in England are getting 100 pounds a year. Besides, +what use was my hair to me? Many people are improved by wearing +it short and perhaps I should be among the number. Next day I was +inclined to think that I had made a mistake, and by the day after +I was sure of it. I had almost overcome my pride so far as to go +back to the agency and inquire whether the place was still open +when I received this letter from the gentleman himself. I have it +here and I will read it to you: + + "'The Copper Beeches, near Winchester. +"'DEAR MISS HUNTER:--Miss Stoper has very kindly given me your +address, and I write from here to ask you whether you have +reconsidered your decision. My wife is very anxious that you +should come, for she has been much attracted by my description of +you. We are willing to give 30 pounds a quarter, or 120 pounds a +year, so as to recompense you for any little inconvenience which +our fads may cause you. They are not very exacting, after all. My +wife is fond of a particular shade of electric blue and would +like you to wear such a dress indoors in the morning. You need +not, however, go to the expense of purchasing one, as we have one +belonging to my dear daughter Alice (now in Philadelphia), which +would, I should think, fit you very well. Then, as to sitting +here or there, or amusing yourself in any manner indicated, that +need cause you no inconvenience. As regards your hair, it is no +doubt a pity, especially as I could not help remarking its beauty +during our short interview, but I am afraid that I must remain +firm upon this point, and I only hope that the increased salary +may recompense you for the loss. Your duties, as far as the child +is concerned, are very light. Now do try to come, and I shall +meet you with the dog-cart at Winchester. Let me know your train. +Yours faithfully, JEPHRO RUCASTLE.' + +"That is the letter which I have just received, Mr. Holmes, and +my mind is made up that I will accept it. I thought, however, +that before taking the final step I should like to submit the +whole matter to your consideration." + +"Well, Miss Hunter, if your mind is made up, that settles the +question," said Holmes, smiling. + +"But you would not advise me to refuse?" + +"I confess that it is not the situation which I should like to +see a sister of mine apply for." + +"What is the meaning of it all, Mr. Holmes?" + +"Ah, I have no data. I cannot tell. Perhaps you have yourself +formed some opinion?" + +"Well, there seems to me to be only one possible solution. Mr. +Rucastle seemed to be a very kind, good-natured man. Is it not +possible that his wife is a lunatic, that he desires to keep the +matter quiet for fear she should be taken to an asylum, and that +he humours her fancies in every way in order to prevent an +outbreak?" + +"That is a possible solution--in fact, as matters stand, it is +the most probable one. But in any case it does not seem to be a +nice household for a young lady." + +"But the money, Mr. Holmes, the money!" + +"Well, yes, of course the pay is good--too good. That is what +makes me uneasy. Why should they give you 120 pounds a year, when +they could have their pick for 40 pounds? There must be some +strong reason behind." + +"I thought that if I told you the circumstances you would +understand afterwards if I wanted your help. I should feel so +much stronger if I felt that you were at the back of me." + +"Oh, you may carry that feeling away with you. I assure you that +your little problem promises to be the most interesting which has +come my way for some months. There is something distinctly novel +about some of the features. If you should find yourself in doubt +or in danger--" + +"Danger! What danger do you foresee?" + +Holmes shook his head gravely. "It would cease to be a danger if +we could define it," said he. "But at any time, day or night, a +telegram would bring me down to your help." + +"That is enough." She rose briskly from her chair with the +anxiety all swept from her face. "I shall go down to Hampshire +quite easy in my mind now. I shall write to Mr. Rucastle at once, +sacrifice my poor hair to-night, and start for Winchester +to-morrow." With a few grateful words to Holmes she bade us both +good-night and bustled off upon her way. + +"At least," said I as we heard her quick, firm steps descending +the stairs, "she seems to be a young lady who is very well able +to take care of herself." + +"And she would need to be," said Holmes gravely. "I am much +mistaken if we do not hear from her before many days are past." + +It was not very long before my friend's prediction was fulfilled. +A fortnight went by, during which I frequently found my thoughts +turning in her direction and wondering what strange side-alley of +human experience this lonely woman had strayed into. The unusual +salary, the curious conditions, the light duties, all pointed to +something abnormal, though whether a fad or a plot, or whether +the man were a philanthropist or a villain, it was quite beyond +my powers to determine. As to Holmes, I observed that he sat +frequently for half an hour on end, with knitted brows and an +abstracted air, but he swept the matter away with a wave of his +hand when I mentioned it. "Data! data! data!" he cried +impatiently. "I can't make bricks without clay." And yet he would +always wind up by muttering that no sister of his should ever +have accepted such a situation. + +The telegram which we eventually received came late one night +just as I was thinking of turning in and Holmes was settling down +to one of those all-night chemical researches which he frequently +indulged in, when I would leave him stooping over a retort and a +test-tube at night and find him in the same position when I came +down to breakfast in the morning. He opened the yellow envelope, +and then, glancing at the message, threw it across to me. + +"Just look up the trains in Bradshaw," said he, and turned back +to his chemical studies. + +The summons was a brief and urgent one. + +"Please be at the Black Swan Hotel at Winchester at midday +to-morrow," it said. "Do come! I am at my wit's end. HUNTER." + +"Will you come with me?" asked Holmes, glancing up. + +"I should wish to." + +"Just look it up, then." + +"There is a train at half-past nine," said I, glancing over my +Bradshaw. "It is due at Winchester at 11:30." + +"That will do very nicely. Then perhaps I had better postpone my +analysis of the acetones, as we may need to be at our best in the +morning." + +By eleven o'clock the next day we were well upon our way to the +old English capital. Holmes had been buried in the morning papers +all the way down, but after we had passed the Hampshire border he +threw them down and began to admire the scenery. It was an ideal +spring day, a light blue sky, flecked with little fleecy white +clouds drifting across from west to east. The sun was shining +very brightly, and yet there was an exhilarating nip in the air, +which set an edge to a man's energy. All over the countryside, +away to the rolling hills around Aldershot, the little red and +grey roofs of the farm-steadings peeped out from amid the light +green of the new foliage. + +"Are they not fresh and beautiful?" I cried with all the +enthusiasm of a man fresh from the fogs of Baker Street. + +But Holmes shook his head gravely. + +"Do you know, Watson," said he, "that it is one of the curses of +a mind with a turn like mine that I must look at everything with +reference to my own special subject. You look at these scattered +houses, and you are impressed by their beauty. I look at them, +and the only thought which comes to me is a feeling of their +isolation and of the impunity with which crime may be committed +there." + +"Good heavens!" I cried. "Who would associate crime with these +dear old homesteads?" + +"They always fill me with a certain horror. It is my belief, +Watson, founded upon my experience, that the lowest and vilest +alleys in London do not present a more dreadful record of sin +than does the smiling and beautiful countryside." + +"You horrify me!" + +"But the reason is very obvious. The pressure of public opinion +can do in the town what the law cannot accomplish. There is no +lane so vile that the scream of a tortured child, or the thud of +a drunkard's blow, does not beget sympathy and indignation among +the neighbours, and then the whole machinery of justice is ever +so close that a word of complaint can set it going, and there is +but a step between the crime and the dock. But look at these +lonely houses, each in its own fields, filled for the most part +with poor ignorant folk who know little of the law. Think of the +deeds of hellish cruelty, the hidden wickedness which may go on, +year in, year out, in such places, and none the wiser. Had this +lady who appeals to us for help gone to live in Winchester, I +should never have had a fear for her. It is the five miles of +country which makes the danger. Still, it is clear that she is +not personally threatened." + +"No. If she can come to Winchester to meet us she can get away." + +"Quite so. She has her freedom." + +"What CAN be the matter, then? Can you suggest no explanation?" + +"I have devised seven separate explanations, each of which would +cover the facts as far as we know them. But which of these is +correct can only be determined by the fresh information which we +shall no doubt find waiting for us. Well, there is the tower of +the cathedral, and we shall soon learn all that Miss Hunter has +to tell." + +The Black Swan is an inn of repute in the High Street, at no +distance from the station, and there we found the young lady +waiting for us. She had engaged a sitting-room, and our lunch +awaited us upon the table. + +"I am so delighted that you have come," she said earnestly. "It +is so very kind of you both; but indeed I do not know what I +should do. Your advice will be altogether invaluable to me." + +"Pray tell us what has happened to you." + +"I will do so, and I must be quick, for I have promised Mr. +Rucastle to be back before three. I got his leave to come into +town this morning, though he little knew for what purpose." + +"Let us have everything in its due order." Holmes thrust his long +thin legs out towards the fire and composed himself to listen. + +"In the first place, I may say that I have met, on the whole, +with no actual ill-treatment from Mr. and Mrs. Rucastle. It is +only fair to them to say that. But I cannot understand them, and +I am not easy in my mind about them." + +"What can you not understand?" + +"Their reasons for their conduct. But you shall have it all just +as it occurred. When I came down, Mr. Rucastle met me here and +drove me in his dog-cart to the Copper Beeches. It is, as he +said, beautifully situated, but it is not beautiful in itself, +for it is a large square block of a house, whitewashed, but all +stained and streaked with damp and bad weather. There are grounds +round it, woods on three sides, and on the fourth a field which +slopes down to the Southampton highroad, which curves past about +a hundred yards from the front door. This ground in front belongs +to the house, but the woods all round are part of Lord +Southerton's preserves. A clump of copper beeches immediately in +front of the hall door has given its name to the place. + +"I was driven over by my employer, who was as amiable as ever, +and was introduced by him that evening to his wife and the child. +There was no truth, Mr. Holmes, in the conjecture which seemed to +us to be probable in your rooms at Baker Street. Mrs. Rucastle is +not mad. I found her to be a silent, pale-faced woman, much +younger than her husband, not more than thirty, I should think, +while he can hardly be less than forty-five. From their +conversation I have gathered that they have been married about +seven years, that he was a widower, and that his only child by +the first wife was the daughter who has gone to Philadelphia. Mr. +Rucastle told me in private that the reason why she had left them +was that she had an unreasoning aversion to her stepmother. As +the daughter could not have been less than twenty, I can quite +imagine that her position must have been uncomfortable with her +father's young wife. + +"Mrs. Rucastle seemed to me to be colourless in mind as well as +in feature. She impressed me neither favourably nor the reverse. +She was a nonentity. It was easy to see that she was passionately +devoted both to her husband and to her little son. Her light grey +eyes wandered continually from one to the other, noting every +little want and forestalling it if possible. He was kind to her +also in his bluff, boisterous fashion, and on the whole they +seemed to be a happy couple. And yet she had some secret sorrow, +this woman. She would often be lost in deep thought, with the +saddest look upon her face. More than once I have surprised her +in tears. I have thought sometimes that it was the disposition of +her child which weighed upon her mind, for I have never met so +utterly spoiled and so ill-natured a little creature. He is small +for his age, with a head which is quite disproportionately large. +His whole life appears to be spent in an alternation between +savage fits of passion and gloomy intervals of sulking. Giving +pain to any creature weaker than himself seems to be his one idea +of amusement, and he shows quite remarkable talent in planning +the capture of mice, little birds, and insects. But I would +rather not talk about the creature, Mr. Holmes, and, indeed, he +has little to do with my story." + +"I am glad of all details," remarked my friend, "whether they +seem to you to be relevant or not." + +"I shall try not to miss anything of importance. The one +unpleasant thing about the house, which struck me at once, was +the appearance and conduct of the servants. There are only two, a +man and his wife. Toller, for that is his name, is a rough, +uncouth man, with grizzled hair and whiskers, and a perpetual +smell of drink. Twice since I have been with them he has been +quite drunk, and yet Mr. Rucastle seemed to take no notice of it. +His wife is a very tall and strong woman with a sour face, as +silent as Mrs. Rucastle and much less amiable. They are a most +unpleasant couple, but fortunately I spend most of my time in the +nursery and my own room, which are next to each other in one +corner of the building. + +"For two days after my arrival at the Copper Beeches my life was +very quiet; on the third, Mrs. Rucastle came down just after +breakfast and whispered something to her husband. + +"'Oh, yes,' said he, turning to me, 'we are very much obliged to +you, Miss Hunter, for falling in with our whims so far as to cut +your hair. I assure you that it has not detracted in the tiniest +iota from your appearance. We shall now see how the electric-blue +dress will become you. You will find it laid out upon the bed in +your room, and if you would be so good as to put it on we should +both be extremely obliged.' + +"The dress which I found waiting for me was of a peculiar shade +of blue. It was of excellent material, a sort of beige, but it +bore unmistakable signs of having been worn before. It could not +have been a better fit if I had been measured for it. Both Mr. +and Mrs. Rucastle expressed a delight at the look of it, which +seemed quite exaggerated in its vehemence. They were waiting for +me in the drawing-room, which is a very large room, stretching +along the entire front of the house, with three long windows +reaching down to the floor. A chair had been placed close to the +central window, with its back turned towards it. In this I was +asked to sit, and then Mr. Rucastle, walking up and down on the +other side of the room, began to tell me a series of the funniest +stories that I have ever listened to. You cannot imagine how +comical he was, and I laughed until I was quite weary. Mrs. +Rucastle, however, who has evidently no sense of humour, never so +much as smiled, but sat with her hands in her lap, and a sad, +anxious look upon her face. After an hour or so, Mr. Rucastle +suddenly remarked that it was time to commence the duties of the +day, and that I might change my dress and go to little Edward in +the nursery. + +"Two days later this same performance was gone through under +exactly similar circumstances. Again I changed my dress, again I +sat in the window, and again I laughed very heartily at the funny +stories of which my employer had an immense répertoire, and which +he told inimitably. Then he handed me a yellow-backed novel, and +moving my chair a little sideways, that my own shadow might not +fall upon the page, he begged me to read aloud to him. I read for +about ten minutes, beginning in the heart of a chapter, and then +suddenly, in the middle of a sentence, he ordered me to cease and +to change my dress. + +"You can easily imagine, Mr. Holmes, how curious I became as to +what the meaning of this extraordinary performance could possibly +be. They were always very careful, I observed, to turn my face +away from the window, so that I became consumed with the desire +to see what was going on behind my back. At first it seemed to be +impossible, but I soon devised a means. My hand-mirror had been +broken, so a happy thought seized me, and I concealed a piece of +the glass in my handkerchief. On the next occasion, in the midst +of my laughter, I put my handkerchief up to my eyes, and was able +with a little management to see all that there was behind me. I +confess that I was disappointed. There was nothing. At least that +was my first impression. At the second glance, however, I +perceived that there was a man standing in the Southampton Road, +a small bearded man in a grey suit, who seemed to be looking in +my direction. The road is an important highway, and there are +usually people there. This man, however, was leaning against the +railings which bordered our field and was looking earnestly up. I +lowered my handkerchief and glanced at Mrs. Rucastle to find her +eyes fixed upon me with a most searching gaze. She said nothing, +but I am convinced that she had divined that I had a mirror in my +hand and had seen what was behind me. She rose at once. + +"'Jephro,' said she, 'there is an impertinent fellow upon the +road there who stares up at Miss Hunter.' + +"'No friend of yours, Miss Hunter?' he asked. + +"'No, I know no one in these parts.' + +"'Dear me! How very impertinent! Kindly turn round and motion to +him to go away.' + +"'Surely it would be better to take no notice.' + +"'No, no, we should have him loitering here always. Kindly turn +round and wave him away like that.' + +"I did as I was told, and at the same instant Mrs. Rucastle drew +down the blind. That was a week ago, and from that time I have +not sat again in the window, nor have I worn the blue dress, nor +seen the man in the road." + +"Pray continue," said Holmes. "Your narrative promises to be a +most interesting one." + +"You will find it rather disconnected, I fear, and there may +prove to be little relation between the different incidents of +which I speak. On the very first day that I was at the Copper +Beeches, Mr. Rucastle took me to a small outhouse which stands +near the kitchen door. As we approached it I heard the sharp +rattling of a chain, and the sound as of a large animal moving +about. + +"'Look in here!' said Mr. Rucastle, showing me a slit between two +planks. 'Is he not a beauty?' + +"I looked through and was conscious of two glowing eyes, and of a +vague figure huddled up in the darkness. + +"'Don't be frightened,' said my employer, laughing at the start +which I had given. 'It's only Carlo, my mastiff. I call him mine, +but really old Toller, my groom, is the only man who can do +anything with him. We feed him once a day, and not too much then, +so that he is always as keen as mustard. Toller lets him loose +every night, and God help the trespasser whom he lays his fangs +upon. For goodness' sake don't you ever on any pretext set your +foot over the threshold at night, for it's as much as your life +is worth.' + +"The warning was no idle one, for two nights later I happened to +look out of my bedroom window about two o'clock in the morning. +It was a beautiful moonlight night, and the lawn in front of the +house was silvered over and almost as bright as day. I was +standing, rapt in the peaceful beauty of the scene, when I was +aware that something was moving under the shadow of the copper +beeches. As it emerged into the moonshine I saw what it was. It +was a giant dog, as large as a calf, tawny tinted, with hanging +jowl, black muzzle, and huge projecting bones. It walked slowly +across the lawn and vanished into the shadow upon the other side. +That dreadful sentinel sent a chill to my heart which I do not +think that any burglar could have done. + +"And now I have a very strange experience to tell you. I had, as +you know, cut off my hair in London, and I had placed it in a +great coil at the bottom of my trunk. One evening, after the +child was in bed, I began to amuse myself by examining the +furniture of my room and by rearranging my own little things. +There was an old chest of drawers in the room, the two upper ones +empty and open, the lower one locked. I had filled the first two +with my linen, and as I had still much to pack away I was +naturally annoyed at not having the use of the third drawer. It +struck me that it might have been fastened by a mere oversight, +so I took out my bunch of keys and tried to open it. The very +first key fitted to perfection, and I drew the drawer open. There +was only one thing in it, but I am sure that you would never +guess what it was. It was my coil of hair. + +"I took it up and examined it. It was of the same peculiar tint, +and the same thickness. But then the impossibility of the thing +obtruded itself upon me. How could my hair have been locked in +the drawer? With trembling hands I undid my trunk, turned out the +contents, and drew from the bottom my own hair. I laid the two +tresses together, and I assure you that they were identical. Was +it not extraordinary? Puzzle as I would, I could make nothing at +all of what it meant. I returned the strange hair to the drawer, +and I said nothing of the matter to the Rucastles as I felt that +I had put myself in the wrong by opening a drawer which they had +locked. + +"I am naturally observant, as you may have remarked, Mr. Holmes, +and I soon had a pretty good plan of the whole house in my head. +There was one wing, however, which appeared not to be inhabited +at all. A door which faced that which led into the quarters of +the Tollers opened into this suite, but it was invariably locked. +One day, however, as I ascended the stair, I met Mr. Rucastle +coming out through this door, his keys in his hand, and a look on +his face which made him a very different person to the round, +jovial man to whom I was accustomed. His cheeks were red, his +brow was all crinkled with anger, and the veins stood out at his +temples with passion. He locked the door and hurried past me +without a word or a look. + +"This aroused my curiosity, so when I went out for a walk in the +grounds with my charge, I strolled round to the side from which I +could see the windows of this part of the house. There were four +of them in a row, three of which were simply dirty, while the +fourth was shuttered up. They were evidently all deserted. As I +strolled up and down, glancing at them occasionally, Mr. Rucastle +came out to me, looking as merry and jovial as ever. + +"'Ah!' said he, 'you must not think me rude if I passed you +without a word, my dear young lady. I was preoccupied with +business matters.' + +"I assured him that I was not offended. 'By the way,' said I, +'you seem to have quite a suite of spare rooms up there, and one +of them has the shutters up.' + +"He looked surprised and, as it seemed to me, a little startled +at my remark. + +"'Photography is one of my hobbies,' said he. 'I have made my +dark room up there. But, dear me! what an observant young lady we +have come upon. Who would have believed it? Who would have ever +believed it?' He spoke in a jesting tone, but there was no jest +in his eyes as he looked at me. I read suspicion there and +annoyance, but no jest. + +"Well, Mr. Holmes, from the moment that I understood that there +was something about that suite of rooms which I was not to know, +I was all on fire to go over them. It was not mere curiosity, +though I have my share of that. It was more a feeling of duty--a +feeling that some good might come from my penetrating to this +place. They talk of woman's instinct; perhaps it was woman's +instinct which gave me that feeling. At any rate, it was there, +and I was keenly on the lookout for any chance to pass the +forbidden door. + +"It was only yesterday that the chance came. I may tell you that, +besides Mr. Rucastle, both Toller and his wife find something to +do in these deserted rooms, and I once saw him carrying a large +black linen bag with him through the door. Recently he has been +drinking hard, and yesterday evening he was very drunk; and when +I came upstairs there was the key in the door. I have no doubt at +all that he had left it there. Mr. and Mrs. Rucastle were both +downstairs, and the child was with them, so that I had an +admirable opportunity. I turned the key gently in the lock, +opened the door, and slipped through. + +"There was a little passage in front of me, unpapered and +uncarpeted, which turned at a right angle at the farther end. +Round this corner were three doors in a line, the first and third +of which were open. They each led into an empty room, dusty and +cheerless, with two windows in the one and one in the other, so +thick with dirt that the evening light glimmered dimly through +them. The centre door was closed, and across the outside of it +had been fastened one of the broad bars of an iron bed, padlocked +at one end to a ring in the wall, and fastened at the other with +stout cord. The door itself was locked as well, and the key was +not there. This barricaded door corresponded clearly with the +shuttered window outside, and yet I could see by the glimmer from +beneath it that the room was not in darkness. Evidently there was +a skylight which let in light from above. As I stood in the +passage gazing at the sinister door and wondering what secret it +might veil, I suddenly heard the sound of steps within the room +and saw a shadow pass backward and forward against the little +slit of dim light which shone out from under the door. A mad, +unreasoning terror rose up in me at the sight, Mr. Holmes. My +overstrung nerves failed me suddenly, and I turned and ran--ran +as though some dreadful hand were behind me clutching at the +skirt of my dress. I rushed down the passage, through the door, +and straight into the arms of Mr. Rucastle, who was waiting +outside. + +"'So,' said he, smiling, 'it was you, then. I thought that it +must be when I saw the door open.' + +"'Oh, I am so frightened!' I panted. + +"'My dear young lady! my dear young lady!'--you cannot think how +caressing and soothing his manner was--'and what has frightened +you, my dear young lady?' + +"But his voice was just a little too coaxing. He overdid it. I +was keenly on my guard against him. + +"'I was foolish enough to go into the empty wing,' I answered. +'But it is so lonely and eerie in this dim light that I was +frightened and ran out again. Oh, it is so dreadfully still in +there!' + +"'Only that?' said he, looking at me keenly. + +"'Why, what did you think?' I asked. + +"'Why do you think that I lock this door?' + +"'I am sure that I do not know.' + +"'It is to keep people out who have no business there. Do you +see?' He was still smiling in the most amiable manner. + +"'I am sure if I had known--' + +"'Well, then, you know now. And if you ever put your foot over +that threshold again'--here in an instant the smile hardened into +a grin of rage, and he glared down at me with the face of a +demon--'I'll throw you to the mastiff.' + +"I was so terrified that I do not know what I did. I suppose that +I must have rushed past him into my room. I remember nothing +until I found myself lying on my bed trembling all over. Then I +thought of you, Mr. Holmes. I could not live there longer without +some advice. I was frightened of the house, of the man, of the +woman, of the servants, even of the child. They were all horrible +to me. If I could only bring you down all would be well. Of +course I might have fled from the house, but my curiosity was +almost as strong as my fears. My mind was soon made up. I would +send you a wire. I put on my hat and cloak, went down to the +office, which is about half a mile from the house, and then +returned, feeling very much easier. A horrible doubt came into my +mind as I approached the door lest the dog might be loose, but I +remembered that Toller had drunk himself into a state of +insensibility that evening, and I knew that he was the only one +in the household who had any influence with the savage creature, +or who would venture to set him free. I slipped in in safety and +lay awake half the night in my joy at the thought of seeing you. +I had no difficulty in getting leave to come into Winchester this +morning, but I must be back before three o'clock, for Mr. and +Mrs. Rucastle are going on a visit, and will be away all the +evening, so that I must look after the child. Now I have told you +all my adventures, Mr. Holmes, and I should be very glad if you +could tell me what it all means, and, above all, what I should +do." + +Holmes and I had listened spellbound to this extraordinary story. +My friend rose now and paced up and down the room, his hands in +his pockets, and an expression of the most profound gravity upon +his face. + +"Is Toller still drunk?" he asked. + +"Yes. I heard his wife tell Mrs. Rucastle that she could do +nothing with him." + +"That is well. And the Rucastles go out to-night?" + +"Yes." + +"Is there a cellar with a good strong lock?" + +"Yes, the wine-cellar." + +"You seem to me to have acted all through this matter like a very +brave and sensible girl, Miss Hunter. Do you think that you could +perform one more feat? I should not ask it of you if I did not +think you a quite exceptional woman." + +"I will try. What is it?" + +"We shall be at the Copper Beeches by seven o'clock, my friend +and I. The Rucastles will be gone by that time, and Toller will, +we hope, be incapable. There only remains Mrs. Toller, who might +give the alarm. If you could send her into the cellar on some +errand, and then turn the key upon her, you would facilitate +matters immensely." + +"I will do it." + +"Excellent! We shall then look thoroughly into the affair. Of +course there is only one feasible explanation. You have been +brought there to personate someone, and the real person is +imprisoned in this chamber. That is obvious. As to who this +prisoner is, I have no doubt that it is the daughter, Miss Alice +Rucastle, if I remember right, who was said to have gone to +America. You were chosen, doubtless, as resembling her in height, +figure, and the colour of your hair. Hers had been cut off, very +possibly in some illness through which she has passed, and so, of +course, yours had to be sacrificed also. By a curious chance you +came upon her tresses. The man in the road was undoubtedly some +friend of hers--possibly her fiancé--and no doubt, as you wore +the girl's dress and were so like her, he was convinced from your +laughter, whenever he saw you, and afterwards from your gesture, +that Miss Rucastle was perfectly happy, and that she no longer +desired his attentions. The dog is let loose at night to prevent +him from endeavouring to communicate with her. So much is fairly +clear. The most serious point in the case is the disposition of +the child." + +"What on earth has that to do with it?" I ejaculated. + +"My dear Watson, you as a medical man are continually gaining +light as to the tendencies of a child by the study of the +parents. Don't you see that the converse is equally valid. I have +frequently gained my first real insight into the character of +parents by studying their children. This child's disposition is +abnormally cruel, merely for cruelty's sake, and whether he +derives this from his smiling father, as I should suspect, or +from his mother, it bodes evil for the poor girl who is in their +power." + +"I am sure that you are right, Mr. Holmes," cried our client. "A +thousand things come back to me which make me certain that you +have hit it. Oh, let us lose not an instant in bringing help to +this poor creature." + +"We must be circumspect, for we are dealing with a very cunning +man. We can do nothing until seven o'clock. At that hour we shall +be with you, and it will not be long before we solve the +mystery." + +We were as good as our word, for it was just seven when we +reached the Copper Beeches, having put up our trap at a wayside +public-house. The group of trees, with their dark leaves shining +like burnished metal in the light of the setting sun, were +sufficient to mark the house even had Miss Hunter not been +standing smiling on the door-step. + +"Have you managed it?" asked Holmes. + +A loud thudding noise came from somewhere downstairs. "That is +Mrs. Toller in the cellar," said she. "Her husband lies snoring +on the kitchen rug. Here are his keys, which are the duplicates +of Mr. Rucastle's." + +"You have done well indeed!" cried Holmes with enthusiasm. "Now +lead the way, and we shall soon see the end of this black +business." + +We passed up the stair, unlocked the door, followed on down a +passage, and found ourselves in front of the barricade which Miss +Hunter had described. Holmes cut the cord and removed the +transverse bar. Then he tried the various keys in the lock, but +without success. No sound came from within, and at the silence +Holmes' face clouded over. + +"I trust that we are not too late," said he. "I think, Miss +Hunter, that we had better go in without you. Now, Watson, put +your shoulder to it, and we shall see whether we cannot make our +way in." + +It was an old rickety door and gave at once before our united +strength. Together we rushed into the room. It was empty. There +was no furniture save a little pallet bed, a small table, and a +basketful of linen. The skylight above was open, and the prisoner +gone. + +"There has been some villainy here," said Holmes; "this beauty +has guessed Miss Hunter's intentions and has carried his victim +off." + +"But how?" + +"Through the skylight. We shall soon see how he managed it." He +swung himself up onto the roof. "Ah, yes," he cried, "here's the +end of a long light ladder against the eaves. That is how he did +it." + +"But it is impossible," said Miss Hunter; "the ladder was not +there when the Rucastles went away." + +"He has come back and done it. I tell you that he is a clever and +dangerous man. I should not be very much surprised if this were +he whose step I hear now upon the stair. I think, Watson, that it +would be as well for you to have your pistol ready." + +The words were hardly out of his mouth before a man appeared at +the door of the room, a very fat and burly man, with a heavy +stick in his hand. Miss Hunter screamed and shrunk against the +wall at the sight of him, but Sherlock Holmes sprang forward and +confronted him. + +"You villain!" said he, "where's your daughter?" + +The fat man cast his eyes round, and then up at the open +skylight. + +"It is for me to ask you that," he shrieked, "you thieves! Spies +and thieves! I have caught you, have I? You are in my power. I'll +serve you!" He turned and clattered down the stairs as hard as he +could go. + +"He's gone for the dog!" cried Miss Hunter. + +"I have my revolver," said I. + +"Better close the front door," cried Holmes, and we all rushed +down the stairs together. We had hardly reached the hall when we +heard the baying of a hound, and then a scream of agony, with a +horrible worrying sound which it was dreadful to listen to. An +elderly man with a red face and shaking limbs came staggering out +at a side door. + +"My God!" he cried. "Someone has loosed the dog. It's not been +fed for two days. Quick, quick, or it'll be too late!" + +Holmes and I rushed out and round the angle of the house, with +Toller hurrying behind us. There was the huge famished brute, its +black muzzle buried in Rucastle's throat, while he writhed and +screamed upon the ground. Running up, I blew its brains out, and +it fell over with its keen white teeth still meeting in the great +creases of his neck. With much labour we separated them and +carried him, living but horribly mangled, into the house. We laid +him upon the drawing-room sofa, and having dispatched the sobered +Toller to bear the news to his wife, I did what I could to +relieve his pain. We were all assembled round him when the door +opened, and a tall, gaunt woman entered the room. + +"Mrs. Toller!" cried Miss Hunter. + +"Yes, miss. Mr. Rucastle let me out when he came back before he +went up to you. Ah, miss, it is a pity you didn't let me know +what you were planning, for I would have told you that your pains +were wasted." + +"Ha!" said Holmes, looking keenly at her. "It is clear that Mrs. +Toller knows more about this matter than anyone else." + +"Yes, sir, I do, and I am ready enough to tell what I know." + +"Then, pray, sit down, and let us hear it for there are several +points on which I must confess that I am still in the dark." + +"I will soon make it clear to you," said she; "and I'd have done +so before now if I could ha' got out from the cellar. If there's +police-court business over this, you'll remember that I was the +one that stood your friend, and that I was Miss Alice's friend +too. + +"She was never happy at home, Miss Alice wasn't, from the time +that her father married again. She was slighted like and had no +say in anything, but it never really became bad for her until +after she met Mr. Fowler at a friend's house. As well as I could +learn, Miss Alice had rights of her own by will, but she was so +quiet and patient, she was, that she never said a word about them +but just left everything in Mr. Rucastle's hands. He knew he was +safe with her; but when there was a chance of a husband coming +forward, who would ask for all that the law would give him, then +her father thought it time to put a stop on it. He wanted her to +sign a paper, so that whether she married or not, he could use +her money. When she wouldn't do it, he kept on worrying her until +she got brain-fever, and for six weeks was at death's door. Then +she got better at last, all worn to a shadow, and with her +beautiful hair cut off; but that didn't make no change in her +young man, and he stuck to her as true as man could be." + +"Ah," said Holmes, "I think that what you have been good enough +to tell us makes the matter fairly clear, and that I can deduce +all that remains. Mr. Rucastle then, I presume, took to this +system of imprisonment?" + +"Yes, sir." + +"And brought Miss Hunter down from London in order to get rid of +the disagreeable persistence of Mr. Fowler." + +"That was it, sir." + +"But Mr. Fowler being a persevering man, as a good seaman should +be, blockaded the house, and having met you succeeded by certain +arguments, metallic or otherwise, in convincing you that your +interests were the same as his." + +"Mr. Fowler was a very kind-spoken, free-handed gentleman," said +Mrs. Toller serenely. + +"And in this way he managed that your good man should have no +want of drink, and that a ladder should be ready at the moment +when your master had gone out." + +"You have it, sir, just as it happened." + +"I am sure we owe you an apology, Mrs. Toller," said Holmes, "for +you have certainly cleared up everything which puzzled us. And +here comes the country surgeon and Mrs. Rucastle, so I think, +Watson, that we had best escort Miss Hunter back to Winchester, +as it seems to me that our locus standi now is rather a +questionable one." + +And thus was solved the mystery of the sinister house with the +copper beeches in front of the door. Mr. Rucastle survived, but +was always a broken man, kept alive solely through the care of +his devoted wife. They still live with their old servants, who +probably know so much of Rucastle's past life that he finds it +difficult to part from them. Mr. Fowler and Miss Rucastle were +married, by special license, in Southampton the day after their +flight, and he is now the holder of a government appointment in +the island of Mauritius. As to Miss Violet Hunter, my friend +Holmes, rather to my disappointment, manifested no further +interest in her when once she had ceased to be the centre of one +of his problems, and she is now the head of a private school at +Walsall, where I believe that she has met with considerable success. + + + + + + + + + +End of the Project Gutenberg EBook of The Adventures of Sherlock Holmes, by +Arthur Conan Doyle + +*** END OF THIS PROJECT GUTENBERG EBOOK THE ADVENTURES OF SHERLOCK HOLMES *** + +***** This file should be named 1661-8.txt or 1661-8.zip ***** +This and all associated files of various formats will be found in: + http://www.gutenberg.org/1/6/6/1661/ + +Produced by an anonymous Project Gutenberg volunteer and Jose Menendez + +Updated editions will replace the previous one--the old editions +will be renamed. + +Creating the works from public domain print editions means that no +one owns a United States copyright in these works, so the Foundation +(and you!) can copy and distribute it in the United States without +permission and without paying copyright royalties. Special rules, +set forth in the General Terms of Use part of this license, apply to +copying and distributing Project Gutenberg-tm electronic works to +protect the PROJECT GUTENBERG-tm concept and trademark. Project +Gutenberg is a registered trademark, and may not be used if you +charge for the eBooks, unless you receive specific permission. If you +do not charge anything for copies of this eBook, complying with the +rules is very easy. You may use this eBook for nearly any purpose +such as creation of derivative works, reports, performances and +research. They may be modified and printed and given away--you may do +practically ANYTHING with public domain eBooks. Redistribution is +subject to the trademark license, especially commercial +redistribution. + + + +*** START: FULL LICENSE *** + +THE FULL PROJECT GUTENBERG LICENSE +PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK + +To protect the Project Gutenberg-tm mission of promoting the free +distribution of electronic works, by using or distributing this work +(or any other work associated in any way with the phrase "Project +Gutenberg"), you agree to comply with all the terms of the Full Project +Gutenberg-tm License (available with this file or online at +http://gutenberg.net/license). + + +Section 1. General Terms of Use and Redistributing Project Gutenberg-tm +electronic works + +1.A. By reading or using any part of this Project Gutenberg-tm +electronic work, you indicate that you have read, understand, agree to +and accept all the terms of this license and intellectual property +(trademark/copyright) agreement. If you do not agree to abide by all +the terms of this agreement, you must cease using and return or destroy +all copies of Project Gutenberg-tm electronic works in your possession. +If you paid a fee for obtaining a copy of or access to a Project +Gutenberg-tm electronic work and you do not agree to be bound by the +terms of this agreement, you may obtain a refund from the person or +entity to whom you paid the fee as set forth in paragraph 1.E.8. + +1.B. "Project Gutenberg" is a registered trademark. It may only be +used on or associated in any way with an electronic work by people who +agree to be bound by the terms of this agreement. There are a few +things that you can do with most Project Gutenberg-tm electronic works +even without complying with the full terms of this agreement. See +paragraph 1.C below. There are a lot of things you can do with Project +Gutenberg-tm electronic works if you follow the terms of this agreement +and help preserve free future access to Project Gutenberg-tm electronic +works. See paragraph 1.E below. + +1.C. The Project Gutenberg Literary Archive Foundation ("the Foundation" +or PGLAF), owns a compilation copyright in the collection of Project +Gutenberg-tm electronic works. Nearly all the individual works in the +collection are in the public domain in the United States. If an +individual work is in the public domain in the United States and you are +located in the United States, we do not claim a right to prevent you from +copying, distributing, performing, displaying or creating derivative +works based on the work as long as all references to Project Gutenberg +are removed. Of course, we hope that you will support the Project +Gutenberg-tm mission of promoting free access to electronic works by +freely sharing Project Gutenberg-tm works in compliance with the terms of +this agreement for keeping the Project Gutenberg-tm name associated with +the work. You can easily comply with the terms of this agreement by +keeping this work in the same format with its attached full Project +Gutenberg-tm License when you share it without charge with others. + +1.D. The copyright laws of the place where you are located also govern +what you can do with this work. Copyright laws in most countries are in +a constant state of change. If you are outside the United States, check +the laws of your country in addition to the terms of this agreement +before downloading, copying, displaying, performing, distributing or +creating derivative works based on this work or any other Project +Gutenberg-tm work. The Foundation makes no representations concerning +the copyright status of any work in any country outside the United +States. + +1.E. Unless you have removed all references to Project Gutenberg: + +1.E.1. The following sentence, with active links to, or other immediate +access to, the full Project Gutenberg-tm License must appear prominently +whenever any copy of a Project Gutenberg-tm work (any work on which the +phrase "Project Gutenberg" appears, or with which the phrase "Project +Gutenberg" is associated) is accessed, displayed, performed, viewed, +copied or distributed: + +This eBook is for the use of anyone anywhere at no cost and with +almost no restrictions whatsoever. You may copy it, give it away or +re-use it under the terms of the Project Gutenberg License included +with this eBook or online at www.gutenberg.net + +1.E.2. If an individual Project Gutenberg-tm electronic work is derived +from the public domain (does not contain a notice indicating that it is +posted with permission of the copyright holder), the work can be copied +and distributed to anyone in the United States without paying any fees +or charges. If you are redistributing or providing access to a work +with the phrase "Project Gutenberg" associated with or appearing on the +work, you must comply either with the requirements of paragraphs 1.E.1 +through 1.E.7 or obtain permission for the use of the work and the +Project Gutenberg-tm trademark as set forth in paragraphs 1.E.8 or +1.E.9. + +1.E.3. If an individual Project Gutenberg-tm electronic work is posted +with the permission of the copyright holder, your use and distribution +must comply with both paragraphs 1.E.1 through 1.E.7 and any additional +terms imposed by the copyright holder. Additional terms will be linked +to the Project Gutenberg-tm License for all works posted with the +permission of the copyright holder found at the beginning of this work. + +1.E.4. Do not unlink or detach or remove the full Project Gutenberg-tm +License terms from this work, or any files containing a part of this +work or any other work associated with Project Gutenberg-tm. + +1.E.5. Do not copy, display, perform, distribute or redistribute this +electronic work, or any part of this electronic work, without +prominently displaying the sentence set forth in paragraph 1.E.1 with +active links or immediate access to the full terms of the Project +Gutenberg-tm License. + +1.E.6. You may convert to and distribute this work in any binary, +compressed, marked up, nonproprietary or proprietary form, including any +word processing or hypertext form. However, if you provide access to or +distribute copies of a Project Gutenberg-tm work in a format other than +"Plain Vanilla ASCII" or other format used in the official version +posted on the official Project Gutenberg-tm web site (www.gutenberg.net), +you must, at no additional cost, fee or expense to the user, provide a +copy, a means of exporting a copy, or a means of obtaining a copy upon +request, of the work in its original "Plain Vanilla ASCII" or other +form. Any alternate format must include the full Project Gutenberg-tm +License as specified in paragraph 1.E.1. + +1.E.7. Do not charge a fee for access to, viewing, displaying, +performing, copying or distributing any Project Gutenberg-tm works +unless you comply with paragraph 1.E.8 or 1.E.9. + +1.E.8. You may charge a reasonable fee for copies of or providing +access to or distributing Project Gutenberg-tm electronic works provided +that + +- You pay a royalty fee of 20% of the gross profits you derive from + the use of Project Gutenberg-tm works calculated using the method + you already use to calculate your applicable taxes. The fee is + owed to the owner of the Project Gutenberg-tm trademark, but he + has agreed to donate royalties under this paragraph to the + Project Gutenberg Literary Archive Foundation. Royalty payments + must be paid within 60 days following each date on which you + prepare (or are legally required to prepare) your periodic tax + returns. Royalty payments should be clearly marked as such and + sent to the Project Gutenberg Literary Archive Foundation at the + address specified in Section 4, "Information about donations to + the Project Gutenberg Literary Archive Foundation." + +- You provide a full refund of any money paid by a user who notifies + you in writing (or by e-mail) within 30 days of receipt that s/he + does not agree to the terms of the full Project Gutenberg-tm + License. You must require such a user to return or + destroy all copies of the works possessed in a physical medium + and discontinue all use of and all access to other copies of + Project Gutenberg-tm works. + +- You provide, in accordance with paragraph 1.F.3, a full refund of any + money paid for a work or a replacement copy, if a defect in the + electronic work is discovered and reported to you within 90 days + of receipt of the work. + +- You comply with all other terms of this agreement for free + distribution of Project Gutenberg-tm works. + +1.E.9. If you wish to charge a fee or distribute a Project Gutenberg-tm +electronic work or group of works on different terms than are set +forth in this agreement, you must obtain permission in writing from +both the Project Gutenberg Literary Archive Foundation and Michael +Hart, the owner of the Project Gutenberg-tm trademark. Contact the +Foundation as set forth in Section 3 below. + +1.F. + +1.F.1. Project Gutenberg volunteers and employees expend considerable +effort to identify, do copyright research on, transcribe and proofread +public domain works in creating the Project Gutenberg-tm +collection. Despite these efforts, Project Gutenberg-tm electronic +works, and the medium on which they may be stored, may contain +"Defects," such as, but not limited to, incomplete, inaccurate or +corrupt data, transcription errors, a copyright or other intellectual +property infringement, a defective or damaged disk or other medium, a +computer virus, or computer codes that damage or cannot be read by +your equipment. + +1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the "Right +of Replacement or Refund" described in paragraph 1.F.3, the Project +Gutenberg Literary Archive Foundation, the owner of the Project +Gutenberg-tm trademark, and any other party distributing a Project +Gutenberg-tm electronic work under this agreement, disclaim all +liability to you for damages, costs and expenses, including legal +fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT +LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE +PROVIDED IN PARAGRAPH 1.F.3. YOU AGREE THAT THE FOUNDATION, THE +TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE +LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR +INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH +DAMAGE. + +1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a +defect in this electronic work within 90 days of receiving it, you can +receive a refund of the money (if any) you paid for it by sending a +written explanation to the person you received the work from. If you +received the work on a physical medium, you must return the medium with +your written explanation. The person or entity that provided you with +the defective work may elect to provide a replacement copy in lieu of a +refund. If you received the work electronically, the person or entity +providing it to you may choose to give you a second opportunity to +receive the work electronically in lieu of a refund. If the second copy +is also defective, you may demand a refund in writing without further +opportunities to fix the problem. + +1.F.4. Except for the limited right of replacement or refund set forth +in paragraph 1.F.3, this work is provided to you 'AS-IS' WITH NO OTHER +WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR ANY PURPOSE. + +1.F.5. Some states do not allow disclaimers of certain implied +warranties or the exclusion or limitation of certain types of damages. +If any disclaimer or limitation set forth in this agreement violates the +law of the state applicable to this agreement, the agreement shall be +interpreted to make the maximum disclaimer or limitation permitted by +the applicable state law. The invalidity or unenforceability of any +provision of this agreement shall not void the remaining provisions. + +1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the +trademark owner, any agent or employee of the Foundation, anyone +providing copies of Project Gutenberg-tm electronic works in accordance +with this agreement, and any volunteers associated with the production, +promotion and distribution of Project Gutenberg-tm electronic works, +harmless from all liability, costs and expenses, including legal fees, +that arise directly or indirectly from any of the following which you do +or cause to occur: (a) distribution of this or any Project Gutenberg-tm +work, (b) alteration, modification, or additions or deletions to any +Project Gutenberg-tm work, and (c) any Defect you cause. + + +Section 2. Information about the Mission of Project Gutenberg-tm + +Project Gutenberg-tm is synonymous with the free distribution of +electronic works in formats readable by the widest variety of computers +including obsolete, old, middle-aged and new computers. It exists +because of the efforts of hundreds of volunteers and donations from +people in all walks of life. + +Volunteers and financial support to provide volunteers with the +assistance they need are critical to reaching Project Gutenberg-tm's +goals and ensuring that the Project Gutenberg-tm collection will +remain freely available for generations to come. In 2001, the Project +Gutenberg Literary Archive Foundation was created to provide a secure +and permanent future for Project Gutenberg-tm and future generations. +To learn more about the Project Gutenberg Literary Archive Foundation +and how your efforts and donations can help, see Sections 3 and 4 +and the Foundation web page at http://www.pglaf.org. + + +Section 3. Information about the Project Gutenberg Literary Archive +Foundation + +The Project Gutenberg Literary Archive Foundation is a non profit +501(c)(3) educational corporation organized under the laws of the +state of Mississippi and granted tax exempt status by the Internal +Revenue Service. The Foundation's EIN or federal tax identification +number is 64-6221541. Its 501(c)(3) letter is posted at +http://pglaf.org/fundraising. Contributions to the Project Gutenberg +Literary Archive Foundation are tax deductible to the full extent +permitted by U.S. federal laws and your state's laws. + +The Foundation's principal office is located at 4557 Melan Dr. S. +Fairbanks, AK, 99712., but its volunteers and employees are scattered +throughout numerous locations. Its business office is located at +809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887, email +business@pglaf.org. Email contact links and up to date contact +information can be found at the Foundation's web site and official +page at http://pglaf.org + +For additional contact information: + Dr. Gregory B. Newby + Chief Executive and Director + gbnewby@pglaf.org + + +Section 4. Information about Donations to the Project Gutenberg +Literary Archive Foundation + +Project Gutenberg-tm depends upon and cannot survive without wide +spread public support and donations to carry out its mission of +increasing the number of public domain and licensed works that can be +freely distributed in machine readable form accessible by the widest +array of equipment including outdated equipment. Many small donations +($1 to $5,000) are particularly important to maintaining tax exempt +status with the IRS. + +The Foundation is committed to complying with the laws regulating +charities and charitable donations in all 50 states of the United +States. Compliance requirements are not uniform and it takes a +considerable effort, much paperwork and many fees to meet and keep up +with these requirements. We do not solicit donations in locations +where we have not received written confirmation of compliance. To +SEND DONATIONS or determine the status of compliance for any +particular state visit http://pglaf.org + +While we cannot and do not solicit contributions from states where we +have not met the solicitation requirements, we know of no prohibition +against accepting unsolicited donations from donors in such states who +approach us with offers to donate. + +International donations are gratefully accepted, but we cannot make +any statements concerning tax treatment of donations received from +outside the United States. U.S. laws alone swamp our small staff. + +Please check the Project Gutenberg Web pages for current donation +methods and addresses. Donations are accepted in a number of other +ways including including checks, online payments and credit card +donations. To donate, please visit: http://pglaf.org/donate + + +Section 5. General Information About Project Gutenberg-tm electronic +works. + +Professor Michael S. Hart is the originator of the Project Gutenberg-tm +concept of a library of electronic works that could be freely shared +with anyone. For thirty years, he produced and distributed Project +Gutenberg-tm eBooks with only a loose network of volunteer support. + + +Project Gutenberg-tm eBooks are often created from several printed +editions, all of which are confirmed as Public Domain in the U.S. +unless a copyright notice is included. Thus, we do not necessarily +keep eBooks in compliance with any particular paper edition. + + +Most people start at our Web site which has the main PG search facility: + + http://www.gutenberg.net + +This Web site includes information about Project Gutenberg-tm, +including how to make donations to the Project Gutenberg Literary +Archive Foundation, how to help produce our new eBooks, and how to +subscribe to our email newsletter to hear about new eBooks. diff --git a/aho-corasick-0.5.3/ctags.rust b/aho-corasick-0.5.3/ctags.rust new file mode 100644 index 000000000..b42edf757 --- /dev/null +++ b/aho-corasick-0.5.3/ctags.rust @@ -0,0 +1,11 @@ +--langdef=Rust +--langmap=Rust:.rs +--regex-Rust=/^[ \t]*(#\[[^\]]\][ \t]*)*(pub[ \t]+)?(extern[ \t]+)?("[^"]+"[ \t]+)?(unsafe[ \t]+)?fn[ \t]+([a-zA-Z0-9_]+)/\6/f,functions,function definitions/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?type[ \t]+([a-zA-Z0-9_]+)/\2/T,types,type definitions/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?enum[ \t]+([a-zA-Z0-9_]+)/\2/g,enum,enumeration names/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?struct[ \t]+([a-zA-Z0-9_]+)/\2/s,structure names/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?mod[ \t]+([a-zA-Z0-9_]+)/\2/m,modules,module names/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?static[ \t]+([a-zA-Z0-9_]+)/\2/c,consts,static constants/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?trait[ \t]+([a-zA-Z0-9_]+)/\2/t,traits,traits/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?impl([ \t\n]+<.*>)?[ \t]+([a-zA-Z0-9_]+)/\3/i,impls,trait implementations/ +--regex-Rust=/^[ \t]*macro_rules![ \t]+([a-zA-Z0-9_]+)/\1/d,macros,macro definitions/ diff --git a/aho-corasick-0.5.3/examples/dict-search.rs b/aho-corasick-0.5.3/examples/dict-search.rs new file mode 100644 index 000000000..e4cb28854 --- /dev/null +++ b/aho-corasick-0.5.3/examples/dict-search.rs @@ -0,0 +1,151 @@ +// This example demonstrates how to use the Aho-Corasick algorithm to rapidly +// scan text for matches in a large dictionary of keywords. This example by +// default reads your system's dictionary (~120,000 words). +extern crate aho_corasick; +extern crate csv; +extern crate docopt; +extern crate memmap; +extern crate rustc_serialize; + +use std::error::Error; +use std::fs::File; +use std::io::{self, BufRead, Write}; +use std::process; + +use aho_corasick::{Automaton, AcAutomaton, Match}; +use docopt::Docopt; +use memmap::{Mmap, Protection}; + +static USAGE: &'static str = " +Usage: dict-search [options] + dict-search --help + +Options: + -d , --dict Path to dictionary of keywords to search. + [default: /usr/share/dict/words] + -m , --min-len The minimum length for a keyword in UTF-8 + encoded bytes. [default: 5] + --overlapping Report overlapping matches. + -c, --count Show only the numebr of matches. + --memory-usage Show memory usage of automaton. + --full Use fully expanded transition matrix. + Warning: may use lots of memory. + -h, --help Show this usage message. +"; + +#[derive(Clone, Debug, RustcDecodable)] +struct Args { + arg_input: String, + flag_dict: String, + flag_min_len: usize, + flag_overlapping: bool, + flag_memory_usage: bool, + flag_full: bool, + flag_count: bool, +} + +fn main() { + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.decode()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(err) => { + writeln!(&mut io::stderr(), "{}", err).unwrap(); + process::exit(1); + } + } +} + +fn run(args: &Args) -> Result<(), Box> { + let aut = try!(build_automaton(&args.flag_dict, args.flag_min_len)); + if args.flag_memory_usage { + let (bytes, states) = if args.flag_full { + let aut = aut.into_full(); + (aut.heap_bytes(), aut.num_states()) + } else { + (aut.heap_bytes(), aut.num_states()) + }; + println!("{} bytes, {} states", bytes, states); + return Ok(()); + } + + if args.flag_full { + let aut = aut.into_full(); + if args.flag_overlapping { + if args.flag_count { + let mmap = Mmap::open_path( + &args.arg_input, Protection::Read).unwrap(); + let text = unsafe { mmap.as_slice() }; + println!("{}", aut.find_overlapping(text).count()); + } else { + let rdr = try!(File::open(&args.arg_input)); + try!(write_matches(&aut, aut.stream_find_overlapping(rdr))); + } + } else { + if args.flag_count { + let mmap = Mmap::open_path( + &args.arg_input, Protection::Read).unwrap(); + let text = unsafe { mmap.as_slice() }; + println!("{}", aut.find(text).count()); + } else { + let rdr = try!(File::open(&args.arg_input)); + try!(write_matches(&aut, aut.stream_find(rdr))); + } + } + } else { + if args.flag_overlapping { + if args.flag_count { + let mmap = Mmap::open_path( + &args.arg_input, Protection::Read).unwrap(); + let text = unsafe { mmap.as_slice() }; + println!("{}", aut.find_overlapping(text).count()); + } else { + let rdr = try!(File::open(&args.arg_input)); + try!(write_matches(&aut, aut.stream_find_overlapping(rdr))); + } + } else { + if args.flag_count { + let mmap = Mmap::open_path( + &args.arg_input, Protection::Read).unwrap(); + let text = unsafe { mmap.as_slice() }; + println!("{}", aut.find(text).count()); + } else { + let rdr = try!(File::open(&args.arg_input)); + try!(write_matches(&aut, aut.stream_find(rdr))); + } + } + } + Ok(()) +} + +fn write_matches(aut: &A, it: I) -> Result<(), Box> + where A: Automaton, I: Iterator> { + let mut wtr = csv::Writer::from_writer(io::stdout()); + try!(wtr.write(["pattern", "start", "end"].iter())); + for m in it { + let m = try!(m); + try!(wtr.write([ + aut.pattern(m.pati), + &m.start.to_string(), + &m.end.to_string(), + ].iter())); + } + try!(wtr.flush()); + Ok(()) +} + +fn build_automaton( + dict_path: &str, + min_len: usize, +) -> Result, Box> { + let buf = io::BufReader::new(try!(File::open(dict_path))); + let mut lines = Vec::with_capacity(1 << 10); + for line in buf.lines() { + let line = try!(line); + if line.len() >= min_len { + lines.push(line); + } + } + Ok(AcAutomaton::with_transitions(lines)) +} diff --git a/aho-corasick-0.5.3/session.vim b/aho-corasick-0.5.3/session.vim new file mode 100644 index 000000000..213c95660 --- /dev/null +++ b/aho-corasick-0.5.3/session.vim @@ -0,0 +1 @@ +au BufWritePost *.rs silent!make ctags > /dev/null 2>&1 diff --git a/aho-corasick-0.5.3/src/autiter.rs b/aho-corasick-0.5.3/src/autiter.rs new file mode 100644 index 000000000..fe67746d8 --- /dev/null +++ b/aho-corasick-0.5.3/src/autiter.rs @@ -0,0 +1,503 @@ +use std::io::{self, BufRead}; +use std::marker::PhantomData; + +use memchr::{memchr, memchr2, memchr3}; + +use super::{ROOT_STATE, StateIdx}; + +/// An abstraction over automatons and their corresponding iterators. +/// The type parameter `P` is the type of the pattern that was used to +/// construct this Automaton. +pub trait Automaton

{ + /// Return the next state given the current state and next character. + fn next_state(&self, si: StateIdx, b: u8) -> StateIdx; + + /// Return true if and only if the given state and current pattern index + /// indicate a match. + fn has_match(&self, si: StateIdx, outi: usize) -> bool; + + /// Build a match given the current state, pattern index and input index. + fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match; + + /// Return the set of bytes that have transitions in the root state. + fn start_bytes(&self) -> &[u8]; + + /// Returns all of the patterns matched by this automaton. + /// + /// The order of the patterns is the order in which they were added. + fn patterns(&self) -> &[P]; + + /// Returns the pattern indexed at `i`. + /// + /// The index corresponds to the position at which the pattern was added + /// to the automaton, starting at `0`. + fn pattern(&self, i: usize) -> &P; + + /// Return the number of patterns in the automaton. + #[inline] + fn len(&self) -> usize { + self.patterns().len() + } + + /// Returns true if the automaton has no patterns. + #[inline] + fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns an iterator of non-overlapping matches in `s`. + fn find<'a, 's, Q: ?Sized + AsRef<[u8]>>( + &'a self, + s: &'s Q, + ) -> Matches<'a, 's, P, Self> + where Self: Sized { + Matches { + aut: self, + text: s.as_ref(), + texti: 0, + si: ROOT_STATE, + _m: PhantomData, + } + } + + /// Returns an iterator of overlapping matches in `s`. + fn find_overlapping<'a, 's, Q: ?Sized + AsRef<[u8]>>( + &'a self, + s: &'s Q, + ) -> MatchesOverlapping<'a, 's, P, Self> + where Self: Sized { + MatchesOverlapping { + aut: self, + text: s.as_ref(), + texti: 0, + si: ROOT_STATE, + outi: 0, + _m: PhantomData, + } + } + + /// Returns an iterator of non-overlapping matches in the given reader. + fn stream_find<'a, R: io::Read>( + &'a self, + rdr: R, + ) -> StreamMatches<'a, R, P, Self> + where Self: Sized { + StreamMatches { + aut: self, + buf: io::BufReader::new(rdr), + texti: 0, + si: ROOT_STATE, + _m: PhantomData, + } + } + + /// Returns an iterator of overlapping matches in the given reader. + fn stream_find_overlapping<'a, R: io::Read>( + &'a self, + rdr: R, + ) -> StreamMatchesOverlapping<'a, R, P, Self> + where Self: Sized { + StreamMatchesOverlapping { + aut: self, + buf: io::BufReader::new(rdr), + texti: 0, + si: ROOT_STATE, + outi: 0, + _m: PhantomData, + } + } +} + +impl<'a, P: AsRef<[u8]>, A: 'a + Automaton

+ ?Sized> + Automaton

for &'a A { + fn next_state(&self, si: StateIdx, b: u8) -> StateIdx { + (**self).next_state(si, b) + } + + fn has_match(&self, si: StateIdx, outi: usize) -> bool { + (**self).has_match(si, outi) + } + + fn start_bytes(&self) -> &[u8] { + (**self).start_bytes() + } + + fn patterns(&self) -> &[P] { + (**self).patterns() + } + + fn pattern(&self, i: usize) -> &P { + (**self).pattern(i) + } + + fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match { + (**self).get_match(si, outi, texti) + } +} + +/// Records a match in the search text. +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Match { + /// The pattern index. + /// + /// This corresponds to the ordering in which the matched pattern was + /// added to the automaton, starting at `0`. + pub pati: usize, + /// The starting byte offset of the match in the search text. + pub start: usize, + /// The ending byte offset of the match in the search text. + /// + /// (This can be re-captiulated with `pati` and adding the pattern's + /// length to `start`, but it is convenient to have it here.) + pub end: usize, +} + +/// An iterator of non-overlapping matches for in-memory text. +/// +/// This iterator yields `Match` values. +/// +/// `'a` is the lifetime of the automaton, `'s` is the lifetime of the +/// search text, and `P` is the type of the Automaton's pattern. +#[derive(Debug)] +pub struct Matches<'a, 's, P, A: 'a + Automaton

+ ?Sized> { + aut: &'a A, + text: &'s [u8], + texti: usize, + si: StateIdx, + _m: PhantomData

, +} + +// When there's an initial lone start byte, it is usually worth it +// to use `memchr` to skip along the input. The problem is that +// the skipping function is called in the inner match loop, which +// can be quite costly if the skipping condition is never met. +// Therefore, we lift the case analysis outside of the inner loop at +// the cost of repeating code. +// +// `step_to_match` is the version of the inner loop without skipping, +// and `skip_to_match` is the version with skipping. +#[inline(never)] +fn step_to_match + ?Sized>( + aut: &A, + text: &[u8], + mut texti: usize, + mut si: StateIdx +) -> Option<(usize, StateIdx)> { + while texti < text.len() { + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + if texti + 4 < text.len() { + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + } + } + None +} + +fn skip_to_match + ?Sized, F: Fn(&A, &[u8], usize) -> usize>( + aut: &A, + text: &[u8], + mut texti: usize, + mut si: StateIdx, + skip: F, +) -> Option<(usize, StateIdx)> { + if si == ROOT_STATE { + texti = skip(aut, text, texti); + } + while texti < text.len() { + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + if si == ROOT_STATE { + texti = skip(aut, text, texti + 1); + } else { + texti += 1; + } + } + None +} + +#[inline] +fn skip1 + ?Sized>( + aut: &A, + text: &[u8], + at: usize, +) -> usize { + debug_assert!(aut.start_bytes().len() == 1); + let b = aut.start_bytes()[0]; + match memchr(b, &text[at..]) { + None => text.len(), + Some(i) => at + i, + } +} + +#[inline] +fn skip2 + ?Sized>( + aut: &A, + text: &[u8], + at: usize, +) -> usize { + debug_assert!(aut.start_bytes().len() == 2); + let (b1, b2) = (aut.start_bytes()[0], aut.start_bytes()[1]); + match memchr2(b1, b2, &text[at..]) { + None => text.len(), + Some(i) => at + i, + } +} + +#[inline] +fn skip3 + ?Sized>( + aut: &A, + text: &[u8], + at: usize, +) -> usize { + debug_assert!(aut.start_bytes().len() == 3); + let (b1, b2, b3) = ( + aut.start_bytes()[0], aut.start_bytes()[1], aut.start_bytes()[2], + ); + match memchr3(b1, b2, b3, &text[at..]) { + None => text.len(), + Some(i) => at + i, + } +} + +impl<'a, 's, P, A: Automaton

+ ?Sized> Iterator for Matches<'a, 's, P, A> { + type Item = Match; + + fn next(&mut self) -> Option { + if self.aut.start_bytes().len() == 1 { + let skip = skip_to_match( + self.aut, self.text, self.texti, self.si, skip1); + if let Some((texti, si)) = skip { + self.texti = texti + 1; + self.si = ROOT_STATE; + return Some(self.aut.get_match(si, 0, texti)); + } + } else if self.aut.start_bytes().len() == 2 { + let skip = skip_to_match( + self.aut, self.text, self.texti, self.si, skip2); + if let Some((texti, si)) = skip { + self.texti = texti + 1; + self.si = ROOT_STATE; + return Some(self.aut.get_match(si, 0, texti)); + } + } else if self.aut.start_bytes().len() == 3 { + let skip = skip_to_match( + self.aut, self.text, self.texti, self.si, skip3); + if let Some((texti, si)) = skip { + self.texti = texti + 1; + self.si = ROOT_STATE; + return Some(self.aut.get_match(si, 0, texti)); + } + } else { + let step = step_to_match(self.aut, self.text, self.texti, self.si); + if let Some((texti, si)) = step { + self.texti = texti + 1; + self.si = ROOT_STATE; + return Some(self.aut.get_match(si, 0, texti)); + } + } + None + } +} + +/// An iterator of non-overlapping matches for streaming text. +/// +/// This iterator yields `io::Result` values. +/// +/// `'a` is the lifetime of the automaton, `R` is the type of the underlying +/// `io::Read`er, and P is the type of the Automaton's pattern. +#[derive(Debug)] +pub struct StreamMatches<'a, R, P, A: 'a + Automaton

+ ?Sized> { + aut: &'a A, + buf: io::BufReader, + texti: usize, + si: StateIdx, + _m: PhantomData

, +} + +impl<'a, R: io::Read, P, A: Automaton

> + Iterator for StreamMatches<'a, R, P, A> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + let mut m = None; + let mut consumed = 0; +'LOOP: loop { + self.buf.consume(consumed); + let bs = match self.buf.fill_buf() { + Err(err) => return Some(Err(err)), + Ok(bs) if bs.len() == 0 => break, + Ok(bs) => bs, + }; + consumed = bs.len(); // is shortened if we find a match + for (i, &b) in bs.iter().enumerate() { + self.si = self.aut.next_state(self.si, b); + if self.aut.has_match(self.si, 0) { + m = Some(Ok(self.aut.get_match(self.si, 0, self.texti))); + consumed = i + 1; + self.texti += 1; + self.si = ROOT_STATE; + break 'LOOP; + } + self.texti += 1; + } + } + self.buf.consume(consumed); + m + } +} + +/// An iterator of overlapping matches for in-memory text. +/// +/// This iterator yields `Match` values. +/// +/// `'a` is the lifetime of the automaton, `'s` is the lifetime of the +/// search text, and `P` is the type of the Automaton's pattern. +#[derive(Debug)] +pub struct MatchesOverlapping<'a, 's, P, A: 'a + Automaton

+ ?Sized> { + aut: &'a A, + text: &'s [u8], + texti: usize, + si: StateIdx, + outi: usize, + _m: PhantomData

, +} + +impl<'a, 's, P, A: Automaton

+ ?Sized> + Iterator for MatchesOverlapping<'a, 's, P, A> { + type Item = Match; + + fn next(&mut self) -> Option { + if self.aut.has_match(self.si, self.outi) { + let m = self.aut.get_match(self.si, self.outi, self.texti); + self.outi += 1; + if !self.aut.has_match(self.si, self.outi) { + self.texti += 1; + } + return Some(m); + } + + self.outi = 0; + if self.aut.start_bytes().len() == 1 { + let skip = skip_to_match( + self.aut, self.text, self.texti, self.si, skip1); + if let Some((texti, si)) = skip { + self.texti = texti; + self.si = si; + return self.next(); + } + } else if self.aut.start_bytes().len() == 2 { + let skip = skip_to_match( + self.aut, self.text, self.texti, self.si, skip2); + if let Some((texti, si)) = skip { + self.texti = texti; + self.si = si; + return self.next(); + } + } else if self.aut.start_bytes().len() == 3 { + let skip = skip_to_match( + self.aut, self.text, self.texti, self.si, skip3); + if let Some((texti, si)) = skip { + self.texti = texti; + self.si = si; + return self.next(); + } + } else { + let step = step_to_match(self.aut, self.text, self.texti, self.si); + if let Some((texti, si)) = step { + self.texti = texti; + self.si = si; + return self.next(); + } + } + None + } +} + +/// An iterator of overlapping matches for streaming text. +/// +/// This iterator yields `io::Result` values. +/// +/// `'a` is the lifetime of the automaton, `R` is the type of the underlying +/// `io::Read`er, and P is the type of the Automaton's pattern. +#[derive(Debug)] +pub struct StreamMatchesOverlapping<'a, R, P, A: 'a + Automaton

+ ?Sized> { + aut: &'a A, + buf: io::BufReader, + texti: usize, + si: StateIdx, + outi: usize, + _m: PhantomData

, +} + +impl<'a, R: io::Read, P, A: Automaton

+ ?Sized> + Iterator for StreamMatchesOverlapping<'a, R, P, A> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + if self.aut.has_match(self.si, self.outi) { + let m = self.aut.get_match(self.si, self.outi, self.texti); + self.outi += 1; + if !self.aut.has_match(self.si, self.outi) { + self.texti += 1; + } + return Some(Ok(m)); + } + let mut m = None; + let mut consumed = 0; + self.outi = 0; +'LOOP: loop { + self.buf.consume(consumed); + let bs = match self.buf.fill_buf() { + Err(err) => return Some(Err(err)), + Ok(bs) if bs.len() == 0 => break, + Ok(bs) => bs, + }; + consumed = bs.len(); // is shortened if we find a match + for (i, &b) in bs.iter().enumerate() { + self.si = self.aut.next_state(self.si, b); + if self.aut.has_match(self.si, self.outi) { + m = Some(Ok(self.aut.get_match( + self.si, self.outi, self.texti))); + consumed = i + 1; + self.outi += 1; + if !self.aut.has_match(self.si, self.outi) { + self.texti += 1; + } + break 'LOOP; + } + self.texti += 1; + } + } + self.buf.consume(consumed); + m + } +} diff --git a/aho-corasick-0.5.3/src/full.rs b/aho-corasick-0.5.3/src/full.rs new file mode 100644 index 000000000..f7d7c637e --- /dev/null +++ b/aho-corasick-0.5.3/src/full.rs @@ -0,0 +1,136 @@ +use std::fmt; +use std::mem; + +use super::{ + FAIL_STATE, + StateIdx, AcAutomaton, Transitions, Match, + usize_bytes, vec_bytes, +}; +use super::autiter::Automaton; + +/// A complete Aho-Corasick automaton. +/// +/// This uses a single transition matrix that permits each input character +/// to move to the next state with a single lookup in the matrix. +/// +/// This is as fast as it gets, but it is guaranteed to use a lot of memory. +/// Namely, it will use at least `4 * 256 * #states`, where the number of +/// states is capped at length of all patterns concatenated. +#[derive(Clone)] +pub struct FullAcAutomaton

{ + pats: Vec

, + trans: Vec, // row-major, where states are rows + out: Vec>, // indexed by StateIdx + start_bytes: Vec, +} + +impl> FullAcAutomaton

{ + /// Build a new expanded Aho-Corasick automaton from an existing + /// Aho-Corasick automaton. + pub fn new(ac: AcAutomaton) -> FullAcAutomaton

{ + let mut fac = FullAcAutomaton { + pats: vec![], + trans: vec![FAIL_STATE; 256 * ac.states.len()], + out: vec![vec![]; ac.states.len()], + start_bytes: vec![], + }; + fac.build_matrix(&ac); + fac.pats = ac.pats; + fac.start_bytes = ac.start_bytes; + fac + } + + #[doc(hidden)] + pub fn memory_usage(&self) -> usize { + self.pats.iter() + .map(|p| vec_bytes() + p.as_ref().len()) + .fold(0, |a, b| a + b) + + (4 * self.trans.len()) + + self.out.iter() + .map(|v| vec_bytes() + (usize_bytes() * v.len())) + .fold(0, |a, b| a + b) + + self.start_bytes.len() + } + + #[doc(hidden)] + pub fn heap_bytes(&self) -> usize { + self.pats.iter() + .map(|p| mem::size_of::

() + p.as_ref().len()) + .fold(0, |a, b| a + b) + + (4 * self.trans.len()) + + self.out.iter() + .map(|v| vec_bytes() + (usize_bytes() * v.len())) + .fold(0, |a, b| a + b) + + self.start_bytes.len() + } + + fn set(&mut self, si: StateIdx, i: u8, goto: StateIdx) { + let ns = self.num_states(); + self.trans[i as usize * ns + si as usize] = goto; + } + + #[doc(hidden)] + #[inline] + pub fn num_states(&self) -> usize { + self.out.len() + } +} + +impl> Automaton

for FullAcAutomaton

{ + #[inline] + fn next_state(&self, si: StateIdx, i: u8) -> StateIdx { + let at = i as usize * self.num_states() + si as usize; + unsafe { *self.trans.get_unchecked(at) } + } + + #[inline] + fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match { + let pati = self.out[si as usize][outi]; + let patlen = self.pats[pati].as_ref().len(); + let start = texti + 1 - patlen; + Match { + pati: pati, + start: start, + end: start + patlen, + } + } + + #[inline] + fn has_match(&self, si: StateIdx, outi: usize) -> bool { + unsafe { outi < self.out.get_unchecked(si as usize).len() } + } + + #[inline] + fn start_bytes(&self) -> &[u8] { + &self.start_bytes + } + + #[inline] + fn patterns(&self) -> &[P] { + &self.pats + } + + #[inline] + fn pattern(&self, i: usize) -> &P { + &self.pats[i] + } +} + +impl> FullAcAutomaton

{ + fn build_matrix(&mut self, ac: &AcAutomaton) { + for (si, s) in ac.states.iter().enumerate().skip(1) { + for b in (0..256).map(|b| b as u8) { + self.set(si as StateIdx, b, ac.next_state(si as StateIdx, b)); + } + for &pati in &s.out { + self.out[si].push(pati); + } + } + } +} + +impl + fmt::Debug> fmt::Debug for FullAcAutomaton

{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "FullAcAutomaton({:?})", self.pats) + } +} diff --git a/aho-corasick-0.5.3/src/lib.rs b/aho-corasick-0.5.3/src/lib.rs new file mode 100644 index 000000000..95ab071f6 --- /dev/null +++ b/aho-corasick-0.5.3/src/lib.rs @@ -0,0 +1,925 @@ +/*! +An implementation of the +[Aho-Corasick string search algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm). + +The Aho-Corasick algorithm is principally useful when you need to search many +large texts for a fixed (possibly large) set of keywords. In particular, the +Aho-Corasick algorithm preprocesses the set of keywords by constructing a +finite state machine. The search phase is then a quick linear scan through the +text. Each character in the search text causes a state transition in the +automaton. Matches are reported when the automaton enters a match state. + +# Examples + +The main type exposed by this crate is `AcAutomaton`, which can be constructed +from an iterator of pattern strings: + +```rust +use aho_corasick::{Automaton, AcAutomaton}; + +let aut = AcAutomaton::new(vec!["apple", "maple"]); + +// AcAutomaton also implements `FromIterator`: +let aut: AcAutomaton<&str> = ["apple", "maple"].iter().cloned().collect(); +``` + +Finding matches can be done with `find`: + +```rust +use aho_corasick::{Automaton, AcAutomaton, Match}; + +let aut = AcAutomaton::new(vec!["apple", "maple"]); +let mut it = aut.find("I like maple apples."); +assert_eq!(it.next(), Some(Match { + pati: 1, + start: 7, + end: 12, +})); +assert_eq!(it.next(), Some(Match { + pati: 0, + start: 13, + end: 18, +})); +assert_eq!(it.next(), None); +``` + +Use `find_overlapping` if you want to report all matches, even if they +overlap with each other. + +```rust +use aho_corasick::{Automaton, AcAutomaton, Match}; + +let aut = AcAutomaton::new(vec!["abc", "a"]); +let matches: Vec<_> = aut.find_overlapping("abc").collect(); +assert_eq!(matches, vec![ + Match { pati: 1, start: 0, end: 1}, Match { pati: 0, start: 0, end: 3 }, +]); + +// Regular `find` will report only one match: +let matches: Vec<_> = aut.find("abc").collect(); +assert_eq!(matches, vec![Match { pati: 1, start: 0, end: 1}]); +``` + +Finally, there are also methods for finding matches on *streams*. Namely, the +search text does not have to live in memory. It's useful to run this on files +that can't fit into memory: + +```no_run +use std::fs::File; + +use aho_corasick::{Automaton, AcAutomaton}; + +let aut = AcAutomaton::new(vec!["foo", "bar", "baz"]); +let rdr = File::open("search.txt").unwrap(); +for m in aut.stream_find(rdr) { + let m = m.unwrap(); // could be an IO error + println!("Pattern '{}' matched at: ({}, {})", + aut.pattern(m.pati), m.start, m.end); +} +``` + +There is also `stream_find_overlapping`, which is just like `find_overlapping`, +but it operates on streams. + +Please see `dict-search.rs` in this crate's `examples` directory for a more +complete example. It creates a large automaton from a dictionary and can do a +streaming match over arbitrarily large data. + +# Memory usage + +A key aspect of an Aho-Corasick implementation is how the state transitions +are represented. The easiest way to make the automaton fast is to store a +sparse 256-slot map in each state. It maps an input byte to a state index. +This makes the matching loop extremely fast, since it translates to a simple +pointer read. + +The problem is that as the automaton accumulates more states, you end up paying +a `256 * 4` (`4` is for the `u32` state index) byte penalty for every state +regardless of how many transitions it has. + +To solve this, only states near the root of the automaton have this sparse +map representation. States near the leaves of the automaton use a dense mapping +that requires a linear scan. + +(The specific limit currently set is `3`, so that states with a depth less than +or equal to `3` are less memory efficient. The result is that the memory usage +of the automaton stops growing rapidly past ~60MB, even for automatons with +thousands of patterns.) + +If you'd like to opt for the less-memory-efficient-but-faster version, then +you can construct an `AcAutomaton` with a `Sparse` transition strategy: + +```rust +use aho_corasick::{Automaton, AcAutomaton, Match, Sparse}; + +let aut = AcAutomaton::<&str, Sparse>::with_transitions(vec!["abc", "a"]); +let matches: Vec<_> = aut.find("abc").collect(); +assert_eq!(matches, vec![Match { pati: 1, start: 0, end: 1}]); +``` +*/ + +#![deny(missing_docs)] + +extern crate memchr; +#[cfg(test)] extern crate quickcheck; +#[cfg(test)] extern crate rand; + +use std::collections::VecDeque; +use std::fmt; +use std::iter::FromIterator; +use std::mem; + +pub use self::autiter::{ + Automaton, Match, + Matches, MatchesOverlapping, StreamMatches, StreamMatchesOverlapping, +}; +pub use self::full::FullAcAutomaton; + +// We're specifying paths explicitly so that we can use +// these modules simultaneously from `main.rs`. +// Should probably make just make `main.rs` a separate crate. +#[path = "autiter.rs"] +mod autiter; +#[path = "full.rs"] +mod full; + +/// The integer type used for the state index. +/// +/// Limiting this to 32 bit integers can have a big impact on memory usage +/// when using the `Sparse` transition representation. +pub type StateIdx = u32; + +// Constants for special state indexes. +const FAIL_STATE: u32 = 0; +const ROOT_STATE: u32 = 1; + +// Limit the depth at which we use a sparse alphabet map. Once the limit is +// reached, a dense set is used (and lookup becomes O(n)). +// +// This does have a performance hit, but the (straight forward) alternative +// is to have a `256 * 4` byte overhead for every state. +// Given that Aho-Corasick is typically used for dictionary searching, this +// can lead to dramatic memory bloat. +// +// This limit should only be increased at your peril. Namely, in the worst +// case, `256^DENSE_DEPTH_THRESHOLD * 4` corresponds to the memory usage in +// bytes. A value of `1` gives us a good balance. This is also a happy point +// in the benchmarks. A value of `0` gives considerably worse times on certain +// benchmarks (e.g., `ac_ten_one_prefix_byte_every_match`) than even a value +// of `1`. A value of `2` is slightly better than `1` and it looks like gains +// level off at that point with not much observable difference when set to +// `3`. +// +// Why not make this user configurable? Well, it doesn't make much sense +// because we pay for it with case analysis in the matching loop. Increasing it +// doesn't have much impact on performance (outside of pathological cases?). +// +// N.B. Someone else seems to have discovered an alternative, but I haven't +// grokked it yet: https://github.com/mischasan/aho-corasick +const DENSE_DEPTH_THRESHOLD: u32 = 1; + +/// An Aho-Corasick finite automaton. +/// +/// The type parameter `P` is the type of the pattern that was used to +/// construct this AcAutomaton. +#[derive(Clone)] +pub struct AcAutomaton { + pats: Vec

, + states: Vec>, + start_bytes: Vec, +} + +#[derive(Clone)] +struct State { + out: Vec, + fail: StateIdx, + goto: T, + depth: u32, +} + +impl> AcAutomaton

{ + /// Create a new automaton from an iterator of patterns. + /// + /// The patterns must be convertible to bytes (`&[u8]`) via the `AsRef` + /// trait. + pub fn new(pats: I) -> AcAutomaton + where I: IntoIterator { + AcAutomaton::with_transitions(pats) + } +} + +impl, T: Transitions> AcAutomaton { + /// Create a new automaton from an iterator of patterns. + /// + /// This constructor allows one to choose the transition representation. + /// + /// The patterns must be convertible to bytes (`&[u8]`) via the `AsRef` + /// trait. + pub fn with_transitions(pats: I) -> AcAutomaton + where I: IntoIterator { + AcAutomaton { + pats: vec![], // filled in later, avoid wrath of borrow checker + states: vec![State::new(0), State::new(0)], // empty and root + start_bytes: vec![], // also filled in later + }.build(pats.into_iter().collect()) + } + + /// Build out the entire automaton into a single matrix. + /// + /// This will make searching as fast as possible at the expense of using + /// at least `4 * 256 * #states` bytes of memory. + pub fn into_full(self) -> FullAcAutomaton

{ + FullAcAutomaton::new(self) + } + + #[doc(hidden)] + pub fn num_states(&self) -> usize { + self.states.len() + } + + #[doc(hidden)] + pub fn heap_bytes(&self) -> usize { + self.pats.iter() + .map(|p| mem::size_of::

() + p.as_ref().len()) + .fold(0, |a, b| a + b) + + self.states.iter() + .map(|s| mem::size_of::>() + s.heap_bytes()) + .fold(0, |a, b| a + b) + + self.start_bytes.len() + } +} + +impl, T: Transitions> Automaton

for AcAutomaton { + #[inline] + fn next_state(&self, mut si: StateIdx, b: u8) -> StateIdx { + loop { + let maybe_si = self.states[si as usize].goto(b); + if maybe_si != FAIL_STATE { + si = maybe_si; + break; + } else { + si = self.states[si as usize].fail; + } + } + si + } + + #[inline] + fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match { + let pati = self.states[si as usize].out[outi]; + let patlen = self.pats[pati].as_ref().len(); + let start = texti + 1 - patlen; + Match { + pati: pati, + start: start, + end: start + patlen, + } + } + + #[inline] + fn has_match(&self, si: StateIdx, outi: usize) -> bool { + outi < self.states[si as usize].out.len() + } + + #[inline] + fn start_bytes(&self) -> &[u8] { + &self.start_bytes + } + + #[inline] + fn patterns(&self) -> &[P] { + &self.pats + } + + #[inline] + fn pattern(&self, i: usize) -> &P { + &self.pats[i] + } +} + +// Below contains code for *building* the automaton. It's a reasonably faithful +// translation of the description/psuedo-code from: +// http://www.cs.uku.fi/~kilpelai/BSA05/lectures/slides04.pdf + +impl, T: Transitions> AcAutomaton { + // This is the first phase and builds the initial keyword tree. + fn build(mut self, pats: Vec

) -> AcAutomaton { + for (pati, pat) in pats.iter().enumerate() { + if pat.as_ref().is_empty() { + continue; + } + let mut previ = ROOT_STATE; + for &b in pat.as_ref() { + if self.states[previ as usize].goto(b) != FAIL_STATE { + previ = self.states[previ as usize].goto(b); + } else { + let depth = self.states[previ as usize].depth + 1; + let nexti = self.add_state(State::new(depth)); + self.states[previ as usize].set_goto(b, nexti); + previ = nexti; + } + } + self.states[previ as usize].out.push(pati); + } + for c in (0..256).into_iter().map(|c| c as u8) { + if self.states[ROOT_STATE as usize].goto(c) == FAIL_STATE { + self.states[ROOT_STATE as usize].set_goto(c, ROOT_STATE); + } else { + self.start_bytes.push(c); + } + } + // If any of the start bytes are non-ASCII, then remove them all, + // because we don't want to be calling memchr on non-ASCII bytes. + // (Well, we could, but it requires being more clever. Simply using + // the prefix byte isn't good enough.) + if self.start_bytes.iter().any(|&b| b > 0x7F) { + self.start_bytes.clear(); + } + self.pats = pats; + self.fill() + } + + // The second phase that fills in the back links. + fn fill(mut self) -> AcAutomaton { + // Fill up the queue with all non-root transitions out of the root + // node. Then proceed by breadth first traversal. + let mut q = VecDeque::new(); + for c in (0..256).into_iter().map(|c| c as u8) { + let si = self.states[ROOT_STATE as usize].goto(c); + if si != ROOT_STATE { + q.push_front(si); + } + } + while let Some(si) = q.pop_back() { + for c in (0..256).into_iter().map(|c| c as u8) { + let u = self.states[si as usize].goto(c); + if u != FAIL_STATE { + q.push_front(u); + let mut v = self.states[si as usize].fail; + while self.states[v as usize].goto(c) == FAIL_STATE { + v = self.states[v as usize].fail; + } + let ufail = self.states[v as usize].goto(c); + self.states[u as usize].fail = ufail; + let ufail_out = self.states[ufail as usize].out.clone(); + self.states[u as usize].out.extend(ufail_out); + } + } + } + self + } + + fn add_state(&mut self, state: State) -> StateIdx { + let i = self.states.len(); + self.states.push(state); + i as StateIdx + } +} + +impl State { + fn new(depth: u32) -> State { + State { + out: vec![], + fail: 1, + goto: Transitions::new(depth), + depth: depth, + } + } + + fn goto(&self, b: u8) -> StateIdx { + self.goto.goto(b) + } + + fn set_goto(&mut self, b: u8, si: StateIdx) { + self.goto.set_goto(b, si); + } + + fn heap_bytes(&self) -> usize { + (self.out.len() * usize_bytes()) + + self.goto.heap_bytes() + } +} + +/// An abstraction over state transition strategies. +/// +/// This is an attempt to let the caller choose the space/time trade offs +/// used for state transitions. +/// +/// (It's possible that this interface is merely good enough for just the two +/// implementations in this crate.) +pub trait Transitions { + /// Return a new state at the given depth. + fn new(depth: u32) -> Self; + /// Return the next state index given the next character. + fn goto(&self, alpha: u8) -> StateIdx; + /// Set the next state index for the character given. + fn set_goto(&mut self, alpha: u8, si: StateIdx); + /// The memory use in bytes (on the heap) of this set of transitions. + fn heap_bytes(&self) -> usize; +} + +/// State transitions that can be stored either sparsely or densely. +/// +/// This uses less space but at the expense of slower matching. +#[derive(Clone, Debug)] +pub struct Dense(DenseChoice); + +#[derive(Clone, Debug)] +enum DenseChoice { + Sparse(Vec), // indexed by alphabet + Dense(Vec<(u8, StateIdx)>), +} + +impl Transitions for Dense { + fn new(depth: u32) -> Dense { + if depth <= DENSE_DEPTH_THRESHOLD { + Dense(DenseChoice::Sparse(vec![0; 256])) + } else { + Dense(DenseChoice::Dense(vec![])) + } + } + + fn goto(&self, b1: u8) -> StateIdx { + match self.0 { + DenseChoice::Sparse(ref m) => m[b1 as usize], + DenseChoice::Dense(ref m) => { + for &(b2, si) in m { + if b1 == b2 { + return si; + } + } + FAIL_STATE + } + } + } + + fn set_goto(&mut self, b: u8, si: StateIdx) { + match self.0 { + DenseChoice::Sparse(ref mut m) => m[b as usize] = si, + DenseChoice::Dense(ref mut m) => m.push((b, si)), + } + } + + fn heap_bytes(&self) -> usize { + match self.0 { + DenseChoice::Sparse(ref m) => m.len() * 4, + DenseChoice::Dense(ref m) => m.len() * (1 + 4), + } + } +} + +/// State transitions that are always sparse. +/// +/// This can use enormous amounts of memory when there are many patterns, +/// but matching is very fast. +#[derive(Clone, Debug)] +pub struct Sparse(Vec); + +impl Transitions for Sparse { + fn new(_: u32) -> Sparse { + Sparse(vec![0; 256]) + } + + #[inline] + fn goto(&self, b: u8) -> StateIdx { + self.0[b as usize] + } + + fn set_goto(&mut self, b: u8, si: StateIdx) { + self.0[b as usize] = si; + } + + fn heap_bytes(&self) -> usize { + self.0.len() * 4 + } +} + +impl> FromIterator for AcAutomaton { + /// Create an automaton from an iterator of strings. + fn from_iter(it: T) -> AcAutomaton where T: IntoIterator { + AcAutomaton::new(it) + } +} + +// Provide some question debug impls for viewing automatons. +// The custom impls mostly exist for special showing of sparse maps. + +impl + fmt::Debug, T: Transitions> + fmt::Debug for AcAutomaton { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use std::iter::repeat; + + try!(writeln!(f, "{}", repeat('-').take(79).collect::())); + try!(writeln!(f, "Patterns: {:?}", self.pats)); + for (i, state) in self.states.iter().enumerate().skip(1) { + try!(writeln!(f, "{:3}: {}", i, state.debug(i == 1))); + } + write!(f, "{}", repeat('-').take(79).collect::()) + } +} + +impl State { + fn debug(&self, root: bool) -> String { + format!("State {{ depth: {:?}, out: {:?}, fail: {:?}, goto: {{{}}} }}", + self.depth, self.out, self.fail, self.goto_string(root)) + } + + fn goto_string(&self, root: bool) -> String { + use std::char::from_u32; + + let mut goto = vec![]; + for b in (0..256).map(|b| b as u8) { + let si = self.goto(b); + if (!root && si == FAIL_STATE) || (root && si == ROOT_STATE) { + continue; + } + goto.push(format!("{} => {}", from_u32(b as u32).unwrap(), si)); + } + goto.join(", ") + } +} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.debug(false)) + } +} + +impl AcAutomaton { + #[doc(hidden)] + pub fn dot(&self) -> String { + use std::fmt::Write; + let mut out = String::new(); + macro_rules! w { + ($w:expr, $($tt:tt)*) => { {write!($w, $($tt)*)}.unwrap() } + } + + w!(out, r#" +digraph automaton {{ + label=<{}>; + labelloc="l"; + labeljust="l"; + rankdir="LR"; +"#, self.pats.join(", ")); + for (i, s) in self.states.iter().enumerate().skip(1) { + let i = i as u32; + if s.out.len() == 0 { + w!(out, " {};\n", i); + } else { + w!(out, " {} [peripheries=2];\n", i); + } + w!(out, " {} -> {} [style=dashed];\n", i, s.fail); + for b in (0..256).map(|b| b as u8) { + let si = s.goto(b); + if si == FAIL_STATE || (i == ROOT_STATE && si == ROOT_STATE) { + continue; + } + w!(out, " {} -> {} [label={}];\n", i, si, b as char); + } + } + w!(out, "}}"); + out + } +} + +fn vec_bytes() -> usize { + usize_bytes() * 3 +} + +fn usize_bytes() -> usize { + let bits = usize::max_value().count_ones() as usize; + bits / 8 +} + +#[cfg(test)] +mod tests { + use std::collections::HashSet; + use std::io; + + use quickcheck::{Arbitrary, Gen, quickcheck}; + + use super::{Automaton, AcAutomaton, Match}; + + fn aut_find(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + AcAutomaton::new(xs.to_vec()).find(&haystack).collect() + } + + fn aut_finds(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + let cur = io::Cursor::new(haystack.as_bytes()); + AcAutomaton::new(xs.to_vec()) + .stream_find(cur).map(|r| r.unwrap()).collect() + } + + fn aut_findf(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + AcAutomaton::new(xs.to_vec()).into_full().find(haystack).collect() + } + + fn aut_findfs(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + let cur = io::Cursor::new(haystack.as_bytes()); + AcAutomaton::new(xs.to_vec()) + .into_full() + .stream_find(cur).map(|r| r.unwrap()).collect() + } + + fn aut_findo(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + AcAutomaton::new(xs.to_vec()).find_overlapping(haystack).collect() + } + + fn aut_findos(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + let cur = io::Cursor::new(haystack.as_bytes()); + AcAutomaton::new(xs.to_vec()) + .stream_find_overlapping(cur).map(|r| r.unwrap()).collect() + } + + fn aut_findfo(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + AcAutomaton::new(xs.to_vec()) + .into_full().find_overlapping(haystack).collect() + } + + fn aut_findfos(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + let cur = io::Cursor::new(haystack.as_bytes()); + AcAutomaton::new(xs.to_vec()) + .into_full() + .stream_find_overlapping(cur).map(|r| r.unwrap()).collect() + } + + #[test] + fn one_pattern_one_match() { + let ns = vec!["a"]; + let hay = "za"; + let matches = vec![ + Match { pati: 0, start: 1, end: 2 }, + ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn one_pattern_many_match() { + let ns = vec!["a"]; + let hay = "zazazzzza"; + let matches = vec![ + Match { pati: 0, start: 1, end: 2 }, + Match { pati: 0, start: 3, end: 4 }, + Match { pati: 0, start: 8, end: 9 }, + ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn one_longer_pattern_one_match() { + let ns = vec!["abc"]; + let hay = "zazabcz"; + let matches = vec![ Match { pati: 0, start: 3, end: 6 } ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn one_longer_pattern_many_match() { + let ns = vec!["abc"]; + let hay = "zazabczzzzazzzabc"; + let matches = vec![ + Match { pati: 0, start: 3, end: 6 }, + Match { pati: 0, start: 14, end: 17 }, + ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn many_pattern_one_match() { + let ns = vec!["a", "b"]; + let hay = "zb"; + let matches = vec![ Match { pati: 1, start: 1, end: 2 } ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn many_pattern_many_match() { + let ns = vec!["a", "b"]; + let hay = "zbzazzzzb"; + let matches = vec![ + Match { pati: 1, start: 1, end: 2 }, + Match { pati: 0, start: 3, end: 4 }, + Match { pati: 1, start: 8, end: 9 }, + ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn many_longer_pattern_one_match() { + let ns = vec!["abc", "xyz"]; + let hay = "zazxyzz"; + let matches = vec![ Match { pati: 1, start: 3, end: 6 } ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn many_longer_pattern_many_match() { + let ns = vec!["abc", "xyz"]; + let hay = "zazxyzzzzzazzzabcxyz"; + let matches = vec![ + Match { pati: 1, start: 3, end: 6 }, + Match { pati: 0, start: 14, end: 17 }, + Match { pati: 1, start: 17, end: 20 }, + ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn many_longer_pattern_overlap_one_match() { + let ns = vec!["abc", "bc"]; + let hay = "zazabcz"; + let matches = vec![ + Match { pati: 0, start: 3, end: 6 }, + Match { pati: 1, start: 4, end: 6 }, + ]; + assert_eq!(&aut_findo(&ns, hay), &matches); + assert_eq!(&aut_findos(&ns, hay), &matches); + assert_eq!(&aut_findfo(&ns, hay), &matches); + assert_eq!(&aut_findfos(&ns, hay), &matches); + } + + #[test] + fn many_longer_pattern_overlap_one_match_reverse() { + let ns = vec!["abc", "bc"]; + let hay = "xbc"; + let matches = vec![ Match { pati: 1, start: 1, end: 3 } ]; + assert_eq!(&aut_findo(&ns, hay), &matches); + assert_eq!(&aut_findos(&ns, hay), &matches); + assert_eq!(&aut_findfo(&ns, hay), &matches); + assert_eq!(&aut_findfos(&ns, hay), &matches); + } + + #[test] + fn many_longer_pattern_overlap_many_match() { + let ns = vec!["abc", "bc", "c"]; + let hay = "zzzabczzzbczzzc"; + let matches = vec![ + Match { pati: 0, start: 3, end: 6 }, + Match { pati: 1, start: 4, end: 6 }, + Match { pati: 2, start: 5, end: 6 }, + Match { pati: 1, start: 9, end: 11 }, + Match { pati: 2, start: 10, end: 11 }, + Match { pati: 2, start: 14, end: 15 }, + ]; + assert_eq!(&aut_findo(&ns, hay), &matches); + assert_eq!(&aut_findos(&ns, hay), &matches); + assert_eq!(&aut_findfo(&ns, hay), &matches); + assert_eq!(&aut_findfos(&ns, hay), &matches); + } + + #[test] + fn many_longer_pattern_overlap_many_match_reverse() { + let ns = vec!["abc", "bc", "c"]; + let hay = "zzzczzzbczzzabc"; + let matches = vec![ + Match { pati: 2, start: 3, end: 4 }, + Match { pati: 1, start: 7, end: 9 }, + Match { pati: 2, start: 8, end: 9 }, + Match { pati: 0, start: 12, end: 15 }, + Match { pati: 1, start: 13, end: 15 }, + Match { pati: 2, start: 14, end: 15 }, + ]; + assert_eq!(&aut_findo(&ns, hay), &matches); + assert_eq!(&aut_findos(&ns, hay), &matches); + assert_eq!(&aut_findfo(&ns, hay), &matches); + assert_eq!(&aut_findfos(&ns, hay), &matches); + } + + #[test] + fn pattern_returns_original_type() { + let aut = AcAutomaton::new(vec!["apple", "maple"]); + + // Explicitly given this type to assert that the thing returned + // from the function is our original type. + let pat: &str = aut.pattern(0); + assert_eq!(pat, "apple"); + + // Also check the return type of the `patterns` function. + let pats: &[&str] = aut.patterns(); + assert_eq!(pats, &["apple", "maple"]); + } + + // Quickcheck time. + + // This generates very small ascii strings, which makes them more likely + // to interact in interesting ways with larger haystack strings. + #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] + pub struct SmallAscii(String); + + impl Arbitrary for SmallAscii { + fn arbitrary(g: &mut G) -> SmallAscii { + use std::char::from_u32; + SmallAscii((0..2) + .map(|_| from_u32(g.gen_range(97, 123)).unwrap()) + .collect()) + } + + fn shrink(&self) -> Box> { + Box::new(self.0.shrink().map(SmallAscii)) + } + } + + impl From for String { + fn from(s: SmallAscii) -> String { s.0 } + } + + impl AsRef<[u8]> for SmallAscii { + fn as_ref(&self) -> &[u8] { self.0.as_ref() } + } + + // This is the same arbitrary impl as `String`, except it has a bias toward + // ASCII characters. + #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] + pub struct BiasAscii(String); + + impl Arbitrary for BiasAscii { + fn arbitrary(g: &mut G) -> BiasAscii { + use std::char::from_u32; + let size = { let s = g.size(); g.gen_range(0, s) }; + let mut s = String::with_capacity(size); + for _ in 0..size { + if g.gen_weighted_bool(3) { + s.push(char::arbitrary(g)); + } else { + for _ in 0..5 { + s.push(from_u32(g.gen_range(97, 123)).unwrap()); + } + } + } + BiasAscii(s) + } + + fn shrink(&self) -> Box> { + Box::new(self.0.shrink().map(BiasAscii)) + } + } + + fn naive_find(xs: &[S], haystack: &str) -> Vec + where S: Clone + Into { + let needles: Vec = + xs.to_vec().into_iter().map(Into::into).collect(); + let mut matches = vec![]; + for hi in 0..haystack.len() { + for (pati, needle) in needles.iter().enumerate() { + let needle = needle.as_bytes(); + if needle.len() == 0 || needle.len() > haystack.len() - hi { + continue; + } + if needle == &haystack.as_bytes()[hi..hi+needle.len()] { + matches.push(Match { + pati: pati, + start: hi, + end: hi + needle.len(), + }); + } + } + } + matches + } + + #[test] + fn qc_ac_equals_naive() { + fn prop(needles: Vec, haystack: BiasAscii) -> bool { + let aut_matches = aut_findo(&needles, &haystack.0); + let naive_matches = naive_find(&needles, &haystack.0); + // Ordering isn't always the same. I don't think we care, so do + // an unordered comparison. + let aset: HashSet = aut_matches.iter().cloned().collect(); + let nset: HashSet = naive_matches.iter().cloned().collect(); + aset == nset + } + quickcheck(prop as fn(Vec, BiasAscii) -> bool); + } +} diff --git a/aho-corasick-0.5.3/src/main.rs b/aho-corasick-0.5.3/src/main.rs new file mode 100644 index 000000000..60562ac6a --- /dev/null +++ b/aho-corasick-0.5.3/src/main.rs @@ -0,0 +1,13 @@ +extern crate memchr; + +use std::env; + +use lib::AcAutomaton; + +#[allow(dead_code)] +mod lib; + +fn main() { + let aut = AcAutomaton::new(env::args().skip(1)); + println!("{}", aut.dot().trim()); +} diff --git a/aho-corasick-0.6.4/.cargo-checksum.json b/aho-corasick-0.6.4/.cargo-checksum.json new file mode 100644 index 000000000..0e38f63c8 --- /dev/null +++ b/aho-corasick-0.6.4/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"} \ No newline at end of file diff --git a/aho-corasick-0.6.4/.travis.yml b/aho-corasick-0.6.4/.travis.yml new file mode 100644 index 000000000..897b3890a --- /dev/null +++ b/aho-corasick-0.6.4/.travis.yml @@ -0,0 +1,13 @@ +language: rust +rust: + - 1.12.0 + - stable + - beta + - nightly +script: + - cargo build --verbose + - cargo test --verbose + - cargo doc + - if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then + cargo bench --verbose; + fi diff --git a/aho-corasick-0.6.4/COPYING b/aho-corasick-0.6.4/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/aho-corasick-0.6.4/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/aho-corasick-0.6.4/Cargo.toml b/aho-corasick-0.6.4/Cargo.toml new file mode 100644 index 000000000..93d5489c7 --- /dev/null +++ b/aho-corasick-0.6.4/Cargo.toml @@ -0,0 +1,68 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "aho-corasick" +version = "0.6.4" +authors = ["Andrew Gallant "] +exclude = ["benches/sherlock.txt"] +description = "Fast multiple substring searching with finite state machines." +homepage = "https://github.com/BurntSushi/aho-corasick" +readme = "README.md" +keywords = ["string", "search", "text", "aho", "corasick"] +license = "Unlicense/MIT" +repository = "https://github.com/BurntSushi/aho-corasick" +[profile.test] +debug = true + +[profile.bench] +debug = true + +[profile.release] +debug = true + +[lib] +name = "aho_corasick" + +[[bin]] +name = "aho-corasick-dot" +test = false +bench = false +doc = false + +[[bench]] +name = "bench" +path = "benches/bench.rs" +test = false +bench = true +[dependencies.memchr] +version = "2" +[dev-dependencies.csv] +version = "0.15" + +[dev-dependencies.docopt] +version = "0.7" + +[dev-dependencies.memmap] +version = "0.5" + +[dev-dependencies.quickcheck] +version = "0.5" +default-features = false + +[dev-dependencies.rand] +version = "0.3" + +[dev-dependencies.rustc-serialize] +version = "0.3" +[badges.travis-ci] +repository = "BurntSushi/aho-corasick" diff --git a/aho-corasick-0.6.4/LICENSE-MIT b/aho-corasick-0.6.4/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/aho-corasick-0.6.4/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/aho-corasick-0.6.4/Makefile b/aho-corasick-0.6.4/Makefile new file mode 100644 index 000000000..9f956f4c4 --- /dev/null +++ b/aho-corasick-0.6.4/Makefile @@ -0,0 +1,14 @@ +all: + echo Nothing to do... + +ctags: + ctags --recurse --options=ctags.rust --languages=Rust + +docs: + cargo doc + in-dir ./target/doc fix-perms + rscp ./target/doc/* gopher:~/www/burntsushi.net/rustdoc/ + +push: + git push origin master + git push github master diff --git a/aho-corasick-0.6.4/README.md b/aho-corasick-0.6.4/README.md new file mode 100644 index 000000000..25e9ef917 --- /dev/null +++ b/aho-corasick-0.6.4/README.md @@ -0,0 +1,55 @@ +This crate provides an implementation of the +[Aho-Corasick](http://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm) +algorithm. Its intended use case is for fast substring matching, particularly +when matching multiple substrings in a search text. This is achieved by +compiling the substrings into a finite state machine. + +This implementation provides optimal algorithmic time complexity. Construction +of the finite state machine is `O(p)` where `p` is the length of the substrings +concatenated. Matching against search text is `O(n + p + m)`, where `n` is +the length of the search text and `m` is the number of matches. + +[![Build status](https://api.travis-ci.org/BurntSushi/aho-corasick.png)](https://travis-ci.org/BurntSushi/aho-corasick) +[![](http://meritbadge.herokuapp.com/aho-corasick)](https://crates.io/crates/aho-corasick) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + + +### Documentation + +[https://docs.rs/aho-corasick/](https://docs.rs/aho-corasick/). + + +### Example + +The documentation contains several examples, and there is a more complete +example as a full program in `examples/dict-search.rs`. + +Here is a quick example showing simple substring matching: + +```rust +use aho_corasick::{Automaton, AcAutomaton, Match}; + +let aut = AcAutomaton::new(vec!["apple", "maple"]); +let mut it = aut.find("I like maple apples."); +assert_eq!(it.next(), Some(Match { + pati: 1, + start: 7, + end: 12, +})); +assert_eq!(it.next(), Some(Match { + pati: 0, + start: 13, + end: 18, +})); +assert_eq!(it.next(), None); +``` + + +### Alternatives + +Aho-Corasick is useful for matching multiple substrings against many long +strings. If your long string is fixed, then you might consider building a +[suffix array](https://github.com/BurntSushi/suffix) +of the search text (which takes `O(n)` time). Matches can then be found in +`O(plogn)` time. diff --git a/aho-corasick-0.6.4/UNLICENSE b/aho-corasick-0.6.4/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/aho-corasick-0.6.4/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/aho-corasick-0.6.4/benches/bench.rs b/aho-corasick-0.6.4/benches/bench.rs new file mode 100644 index 000000000..d51bcaeec --- /dev/null +++ b/aho-corasick-0.6.4/benches/bench.rs @@ -0,0 +1,339 @@ +#![feature(test)] + +extern crate aho_corasick; +extern crate test; + +use std::iter; + +use aho_corasick::{Automaton, AcAutomaton, Transitions}; +use test::Bencher; + +const HAYSTACK_RANDOM: &'static str = include_str!("random.txt"); +const HAYSTACK_SHERLOCK: &'static str = include_str!("sherlock.txt"); + +fn bench_aut_no_match, T: Transitions>( + b: &mut Bencher, + aut: AcAutomaton, + haystack: &str, +) { + b.bytes = haystack.len() as u64; + b.iter(|| assert!(aut.find(haystack).next().is_none())); +} + +fn bench_box_aut_no_match, T: Transitions>( + b: &mut Bencher, + aut: AcAutomaton, + haystack: &str, +) { + b.bytes = haystack.len() as u64; + let aut: &Automaton

= &aut; + b.iter(|| assert!(Automaton::find(&aut, haystack).next().is_none())); +} + +fn bench_full_aut_no_match, T: Transitions>( + b: &mut Bencher, + aut: AcAutomaton, + haystack: &str, +) { + let aut = aut.into_full(); + b.bytes = haystack.len() as u64; + b.iter(|| assert!(aut.find(haystack).next().is_none())); +} + +fn bench_full_aut_overlapping_no_match, T: Transitions>( + b: &mut Bencher, + aut: AcAutomaton, + haystack: &str, +) { + let aut = aut.into_full(); + b.bytes = haystack.len() as u64; + b.iter(|| assert!(aut.find_overlapping(haystack).count() == 0)); +} + +fn bench_naive_no_match(b: &mut Bencher, needles: Vec, haystack: &str) + where S: Into { + b.bytes = haystack.len() as u64; + let needles: Vec = needles.into_iter().map(Into::into).collect(); + b.iter(|| assert!(!naive_find(&needles, haystack))); +} + +fn haystack_same(letter: char) -> String { + iter::repeat(letter).take(10000).collect() +} + +macro_rules! aut_benches { + ($prefix:ident, $aut:expr, $bench:expr) => { + mod $prefix { +#![allow(unused_imports)] +use aho_corasick::{Automaton, AcAutomaton, Sparse}; +use test::Bencher; + +use super::{ + HAYSTACK_RANDOM, haystack_same, + bench_aut_no_match, bench_box_aut_no_match, + bench_full_aut_no_match, bench_full_aut_overlapping_no_match, +}; + +#[bench] +fn ac_one_byte(b: &mut Bencher) { + let aut = $aut(vec!["a"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_one_prefix_byte_no_match(b: &mut Bencher) { + let aut = $aut(vec!["zbc"]); + $bench(b, aut, &haystack_same('y')); +} + +#[bench] +fn ac_one_prefix_byte_every_match(b: &mut Bencher) { + // We lose the benefit of `memchr` because the first byte matches + // in every position in the haystack. + let aut = $aut(vec!["zbc"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_one_prefix_byte_random(b: &mut Bencher) { + let aut = $aut(vec!["zbc\x00"]); + $bench(b, aut, HAYSTACK_RANDOM); +} + +#[bench] +fn ac_two_bytes(b: &mut Bencher) { + let aut = $aut(vec!["a", "b"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_two_diff_prefix(b: &mut Bencher) { + let aut = $aut(vec!["abcdef", "bmnopq"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_two_one_prefix_byte_every_match(b: &mut Bencher) { + let aut = $aut(vec!["zbcdef", "zmnopq"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_two_one_prefix_byte_no_match(b: &mut Bencher) { + let aut = $aut(vec!["zbcdef", "zmnopq"]); + $bench(b, aut, &haystack_same('y')); +} + +#[bench] +fn ac_two_one_prefix_byte_random(b: &mut Bencher) { + let aut = $aut(vec!["zbcdef\x00", "zmnopq\x00"]); + $bench(b, aut, HAYSTACK_RANDOM); +} + +#[bench] +fn ac_ten_bytes(b: &mut Bencher) { + let aut = $aut(vec!["a", "b", "c", "d", "e", + "f", "g", "h", "i", "j"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_ten_diff_prefix(b: &mut Bencher) { + let aut = $aut(vec!["abcdef", "bbcdef", "cbcdef", "dbcdef", + "ebcdef", "fbcdef", "gbcdef", "hbcdef", + "ibcdef", "jbcdef"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_ten_one_prefix_byte_every_match(b: &mut Bencher) { + let aut = $aut(vec!["zacdef", "zbcdef", "zccdef", "zdcdef", + "zecdef", "zfcdef", "zgcdef", "zhcdef", + "zicdef", "zjcdef"]); + $bench(b, aut, &haystack_same('z')); +} + +#[bench] +fn ac_ten_one_prefix_byte_no_match(b: &mut Bencher) { + let aut = $aut(vec!["zacdef", "zbcdef", "zccdef", "zdcdef", + "zecdef", "zfcdef", "zgcdef", "zhcdef", + "zicdef", "zjcdef"]); + $bench(b, aut, &haystack_same('y')); +} + +#[bench] +fn ac_ten_one_prefix_byte_random(b: &mut Bencher) { + let aut = $aut(vec!["zacdef\x00", "zbcdef\x00", "zccdef\x00", + "zdcdef\x00", "zecdef\x00", "zfcdef\x00", + "zgcdef\x00", "zhcdef\x00", "zicdef\x00", + "zjcdef\x00"]); + $bench(b, aut, HAYSTACK_RANDOM); +} + } + } +} + +aut_benches!(dense, AcAutomaton::new, bench_aut_no_match); +aut_benches!(dense_boxed, AcAutomaton::new, bench_box_aut_no_match); +aut_benches!(sparse, AcAutomaton::<&str, Sparse>::with_transitions, + bench_aut_no_match); +aut_benches!(full, AcAutomaton::new, bench_full_aut_no_match); +aut_benches!(full_overlap, AcAutomaton::new, bench_full_aut_overlapping_no_match); + +// A naive multi-pattern search. +// We use this to benchmark *throughput*, so it should never match anything. +fn naive_find(needles: &[String], haystack: &str) -> bool { + for hi in 0..haystack.len() { + let rest = &haystack.as_bytes()[hi..]; + for needle in needles { + let needle = needle.as_bytes(); + if needle.len() > rest.len() { + continue; + } + if needle == &rest[..needle.len()] { + // should never happen in throughput benchmarks. + return true; + } + } + } + false +} + +#[bench] +fn naive_one_byte(b: &mut Bencher) { + bench_naive_no_match(b, vec!["a"], &haystack_same('z')); +} + +#[bench] +fn naive_one_prefix_byte_no_match(b: &mut Bencher) { + bench_naive_no_match(b, vec!["zbc"], &haystack_same('y')); +} + +#[bench] +fn naive_one_prefix_byte_every_match(b: &mut Bencher) { + bench_naive_no_match(b, vec!["zbc"], &haystack_same('z')); +} + +#[bench] +fn naive_one_prefix_byte_random(b: &mut Bencher) { + bench_naive_no_match(b, vec!["zbc\x00"], HAYSTACK_RANDOM); +} + +#[bench] +fn naive_two_bytes(b: &mut Bencher) { + bench_naive_no_match(b, vec!["a", "b"], &haystack_same('z')); +} + +#[bench] +fn naive_two_diff_prefix(b: &mut Bencher) { + bench_naive_no_match(b, vec!["abcdef", "bmnopq"], &haystack_same('z')); +} + +#[bench] +fn naive_two_one_prefix_byte_every_match(b: &mut Bencher) { + bench_naive_no_match(b, vec!["zbcdef", "zmnopq"], &haystack_same('z')); +} + +#[bench] +fn naive_two_one_prefix_byte_no_match(b: &mut Bencher) { + bench_naive_no_match(b, vec!["zbcdef", "zmnopq"], &haystack_same('y')); +} + +#[bench] +fn naive_two_one_prefix_byte_random(b: &mut Bencher) { + bench_naive_no_match(b, vec!["zbcdef\x00", "zmnopq\x00"], HAYSTACK_RANDOM); +} + +#[bench] +fn naive_ten_bytes(b: &mut Bencher) { + let needles = vec!["a", "b", "c", "d", "e", + "f", "g", "h", "i", "j"]; + bench_naive_no_match(b, needles, &haystack_same('z')); +} + +#[bench] +fn naive_ten_diff_prefix(b: &mut Bencher) { + let needles = vec!["abcdef", "bbcdef", "cbcdef", "dbcdef", + "ebcdef", "fbcdef", "gbcdef", "hbcdef", + "ibcdef", "jbcdef"]; + bench_naive_no_match(b, needles, &haystack_same('z')); +} + +#[bench] +fn naive_ten_one_prefix_byte_every_match(b: &mut Bencher) { + let needles = vec!["zacdef", "zbcdef", "zccdef", "zdcdef", + "zecdef", "zfcdef", "zgcdef", "zhcdef", + "zicdef", "zjcdef"]; + bench_naive_no_match(b, needles, &haystack_same('z')); +} + +#[bench] +fn naive_ten_one_prefix_byte_no_match(b: &mut Bencher) { + let needles = vec!["zacdef", "zbcdef", "zccdef", "zdcdef", + "zecdef", "zfcdef", "zgcdef", "zhcdef", + "zicdef", "zjcdef"]; + bench_naive_no_match(b, needles, &haystack_same('y')); +} + +#[bench] +fn naive_ten_one_prefix_byte_random(b: &mut Bencher) { + let needles = vec!["zacdef\x00", "zbcdef\x00", "zccdef\x00", + "zdcdef\x00", "zecdef\x00", "zfcdef\x00", + "zgcdef\x00", "zhcdef\x00", "zicdef\x00", + "zjcdef\x00"]; + bench_naive_no_match(b, needles, HAYSTACK_RANDOM); +} + + +// The organization above is just awful. Let's start over... + +mod sherlock { + use aho_corasick::{Automaton, AcAutomaton}; + use test::Bencher; + use super::HAYSTACK_SHERLOCK; + + macro_rules! sherlock { + ($name:ident, $count:expr, $pats:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let haystack = HAYSTACK_SHERLOCK; + let aut = AcAutomaton::new($pats).into_full(); + b.bytes = haystack.len() as u64; + b.iter(|| assert_eq!($count, aut.find(haystack).count())); + } + } + } + + sherlock!(name_alt1, 158, vec!["Sherlock", "Street"]); + + sherlock!(name_alt2, 558, vec!["Sherlock", "Holmes"]); + + sherlock!(name_alt3, 740, vec![ + "Sherlock", "Holmes", "Watson", "Irene", "Adler", "John", "Baker", + ]); + + sherlock!(name_alt3_nocase, 1764, vec![ + "ADL", "ADl", "AdL", "Adl", "BAK", "BAk", "BAK", "BaK", "Bak", "BaK", + "HOL", "HOl", "HoL", "Hol", "IRE", "IRe", "IrE", "Ire", "JOH", "JOh", + "JoH", "Joh", "SHE", "SHe", "ShE", "She", "WAT", "WAt", "WaT", "Wat", + "aDL", "aDl", "adL", "adl", "bAK", "bAk", "bAK", "baK", "bak", "baK", + "hOL", "hOl", "hoL", "hol", "iRE", "iRe", "irE", "ire", "jOH", "jOh", + "joH", "joh", "sHE", "sHe", "shE", "she", "wAT", "wAt", "waT", "wat", + "ſHE", "ſHe", "ſhE", "ſhe", + ]); + + sherlock!(name_alt4, 582, vec!["Sher", "Hol"]); + + sherlock!(name_alt4_nocase, 1307, vec![ + "HOL", "HOl", "HoL", "Hol", "SHE", "SHe", "ShE", "She", "hOL", "hOl", + "hoL", "hol", "sHE", "sHe", "shE", "she", "ſHE", "ſHe", "ſhE", "ſhe", + ]); + + sherlock!(name_alt5, 639, vec!["Sherlock", "Holmes", "Watson"]); + + sherlock!(name_alt5_nocase, 1442, vec![ + "HOL", "HOl", "HoL", "Hol", "SHE", "SHe", "ShE", "She", "WAT", "WAt", + "WaT", "Wat", "hOL", "hOl", "hoL", "hol", "sHE", "sHe", "shE", "she", + "wAT", "wAt", "waT", "wat", "ſHE", "ſHe", "ſhE", "ſhe", + ]); +} diff --git a/aho-corasick-0.6.4/benches/random.txt b/aho-corasick-0.6.4/benches/random.txt new file mode 100644 index 000000000..dfae5cd14 --- /dev/null +++ b/aho-corasick-0.6.4/benches/random.txt @@ -0,0 +1,513 @@ + +mnxnsynfvuugtbxsxbfxwreuspglnplefzwsp +tacfqcwnmodnmgnyiuvqoco +z + +qjuozfkexn +zoaxzncje +sldhqtmgxzyurfyzwazmmu +bbeuv +mzsrihycwcb +xzfqozfmlnpmrzpxxxytqs +xrg +mcplby +nmslhfgjowhzfxsvyddydnsyehdskbydbjksqtpet +indvfw +bvjvvw + +pddufodyqtyixbndtumndyz +xjjhtuvmsxhuwqulqtjhqrdqrmtbcphvyuqllocrnkpfv +zemshhz +wss +xewlrxfmgxnwgphcgefa +mbgsgbzrtthxweimcqzcaaheurdmd +osqefupespvh +z +tvvlakwzwjbrgjzfgubsmmonav +pjdskxcfgapsm +zqktqgkrcdrlskx +zwwfebhguskho +zlvvw +czwm +gojnpmboehlsazbexjjnuscqftrfufngygjdxcydib +d +afigycivicnknfxl +ljuwuopctiftfwctxecwipjnljyef +jonwbkodomzhqvlf +jdkizhognqsdogunwedjsmsdzho +zxvni +oynfjf +muvokjuqz +azuwrwtuxzfopwrcex +ixrjinlvxjmn +blaegnmbhsgsbmebwazaeguugtkowexgnqtbfkldadddv +tzabyoftyov +ctbtqbzscxzviuvcigwuwusrdro +ljynr +gnnnyyxslrhsbj +hhzlw +hijalf +rxlfqk +mhaofforwznvmcgplinludpgkucpa +gvvxsqqfmu +xxqhoyosixjfhjuxpv +faadjpvamjekreepizurntvwdynozfawsfawyms + +lcbutr +aqyxvpozkjrecrkl +lfmochahrr +ptqyomjlwo +vcmslulznx +lmlsskcihrmxauztuarydlp +beiqsrfnmvmlmybmwpektjbikvpggthpabqsgmjhnthvysuhwbigillugjsp +dfsuegseffwcsnvsrqedytblbpzbfeyfsq +kypvqctrkuds +ylqeduokzgdqaxelhftxnxbidu +bprzyayfopxdsmfhhfqowa +ymiutdtlfaaxpbtaeslv +ggago + +owpbicekdeykzfgcbgzobdvvrtetvcv +xsrlgingstiez +gyncqvq +xasohmeiwyscpehctmzmsnjklg +xsudghakxlw +dzqlfptjogzpkvwuticcyugnyopypuqqc +wlxshxbhdvuherumoppcc + +znyaptivzncvkpeyeipynqefjxjjcsgfqbnezeebtowdrbjaqjlbxwvyikrmxjwoxngqgvfpbniftnmszuxg +umwpwwyvufy +pallkjtnrmtauqxauewgygwkjjwebbkabhtxticxmxfujpxlrpzlrozfslkzfdsswlmmsbdgjwmjnummk +dhsxylejzityahtqqzmohrpzjprrsraztpnuagtyzfjdekthvdogfidksrdppr +ybc +fyukknoqfnkllkwflwempjijxgo +dltvlau +rhvrvlwsribfctuzodfqkdczfzxnetqqzflnhiyl +goxmcasmq +wljbhwkpahdotqhhrbhqzijv +lszewkgdmkezvgmbmllhpksdkoiwgkvqjmurshrptlctqsosuurndcuzjfwherotv +dudxxihygxblhgchbgzyzffb +eht +fvwxvqoltdcsd +rkuig +e +axhsacsmnicugul +rubtdlhjqndxdzzwfnkuzy +swxteuyxxsktkjgv +hzwwodlqaq +vxgecev +qnwla +vdxjuzpyoqhpmuunyffptopmeauhycs +dkzo +awrfzatzohslgvqlaezepmli +qgxatixvpkkhvkumbwmwcagtgyfljdok +amdnzstpvcqj +xsrvwvhjirzfgkessve +qezwbfltfbikbmoasvoflozsjhrljnszqiciuqmflrlqowwkoevuumh +babskcvavmtvsxqsewirucwzajjcfcqwsydydqo +ywfurpsl +edacsjjkjjewkxfoh +dcgkfpcjezurnuhiatrczcp +xsatnimwbcciu +grzmbrsvvcyigcbmcqfwiiknrohveubhyijxeyzfm +kqyewccgcqrrrznwxmoztlyseagbpyho +najju +nis +awgzdvfjkzlrsjcqfeacx +oisuflfigrjaex +desbdulyuwqxuxianyypybxwlql +ekmqgspvqpftpwswayh +egbyj +fznzprhvnnwcxgcc +wfdsueieosmugirxbymbpmfrspvrktjzguxm +qkjrufshwnfwwpbhukdjlaqvljlgubmqmhnha +hwqpudgnblhlxppbrmbznotteivuzguuwlhtkytky +w +yofkyzbpg +cenolnfnllkvhikrpttcxgqxmufvorekjruyjxmr + +hyexmpjijgzumawp +cdbevdilgopbzlo +fivelagckslkugdxprjxkylizewcptwxfhomzuituujixchadmnjoktnqa +csojvlinzmmkkfzqueamnuwkanzdzsavgohposbuoamoevehqrmcxdsuyelvvctoejzoertqormhaaxwofvjzekwt +sbkghhnhutrvwtyjaxndzyjamrhx +jjyqy +majwbnrhveuhrsbbbjrwpwuplifeseylqh +wyvutpxnkrnkuxxetjkkifpqb +dyzucmbcvgnjeecm +hz +uhnuipthxrzkqluosvk +lwqqzsdwiwvwaqfwlvubadlyizlo +jbd +oyzjeu +kydjkbsqxnbfiuesc +smeubjqrcxdvhsabzceyglqjzbfmoacmwvwjbhhxbr +uabipgecujfdfxpmdzrscdyvefizabgspqjrrkmgjt +xgvdgzryz +lw +uimob +ifhn +bqph +ole +g +wt +k +yslzrkwkundxfdibwqvucemepqxlmlpyngabbeciuzhptpjdetyngrtxrdtzmvq +ccwapidp + +bwvrgvmtshevrophy +ni +fdkplu +mdykey +i +rhsrenoetdggpjb +djmkplpeabsholx +judxtub +fooakqwvocvpcrvxqhvtmpvhkrecy +uuxscjillynilbkrgt +evtinrmilniguarqritpeipwochmdw +sxaqzjybydyvnmmjtdcgkjnqfcklbfpkdfyewgcukqoiegyfp +kg +ovrwieqhy +jcxqtkerzjwhs +xeonglszbgypafhmqcaseimzjgebkvigbqwsayrnrprtuvhsxyitfqygohgorcdnufbcyvevvgzmjrgjqqquwkszplogx +zdketqqv +yebckucwayckeezfvtnavglpjh +zorkfrwk +pad +xqaquxudybwtgixbfktinctfirjfdayh +rieknj +ebk +qzbcfywfdmhsdruhopovemafijbscagllkmhmof + +asbsnbddlobwoqatfhkbhhsymzqxjuixwreheugvngmgcuqpkjhhfwpbarqaxrwgwnjbanljlds +etevdvlc +lqyjrnmenhn +k +tsf +zczgeavcexh +jlpuxywtsrvnvluruqhecjca +ir +rikrgkmhwaosodkxgcnrexfmdrszhnmutpvwztg +bffjqovvkemctnsgeh +weysbhzixiipfithjfsk +usyzvaiyuhmksfluoirfbnsu +o +cgawpdakaszeafdtbdkqtlzkrpnoqomqvuaqcfmzgvfegovtfaonelpv +izmrcjlk +xmzemniyrzy +knqexaafsdlimdamcrprlshq +qkmqw +dntgjwsibclvposdwjuklvtejjjdjibgpyynqpgprvvaetshhmvfkcpb +otvazkrkklrxfotpopyjte +fghkcnpi +rulyaihsowvcgbzeiblhuhhfbmncqsuuqcxvseorn +exirzfmojnxcoqom +zsgpgtokun +zvamxfocorganbtlafifwdqmqtsnktbwwtewborq + +cxlnaspjqvsitjyzyriqsuorjsrvzqenisprttudxntsbqrpjtdkxnwcwgjyxmgtqljcrmrbrmyvosojzlumcmjcgfjsdehec +mvx +mt +mckr +teulvroifk +laaicc +koufy +bexmwsvyarnznebdfy +ripvviosbqijsxnjilwddaqaqemzsdarnxmfooxghoypizwtbueo +ljycycuqwfnzbambibqdixmkkvwtubepla +cis +kcg +vmbbiuuoamenzepuagpfujevfstqtndjxjchdvycfrrrowochtjdmkklgnhf +pmorrwguxkvdxpluatagaziin + +uwvzbmkmykjkmknzppklx +pnzxuvsrjunqxercsnvayhykcazdeclomdsasgkpqpiufyfqsxhj +yceizkddwojgweegcllaagpvrpo +ek +kuxxgbezqyxvfaxdwnqdgqsmneijunxzlwxkrs +ldldbrxmvtjlqxifngmactzqcygkvuteffcmvphevilabgukatqakamjlridznodcvblvlogulmcixxfimh +iuzjootuywjqklolzzhpeaynydjwtufjavbozxnzckuzdodkvkjfmhinelv +swlfkcufscfcovmghqwcrtxjukwafoeogrkgubbqgwzm +gjcylkwgzroubdssuqeykqjcmguso +fzq +srfvysoxtlylctp + +pbfeiuzwoyixews +ocvvunfsjnrtklmuuzjojw +xdjcnrpqhmpmpcwacpcdtmbsczvhllkqapzjuaf +nfnuvjz +fwnuiyqpn +wshxxxpzzxp +hibrxcfeqca + +wqhlllarl +bukcbojv +plrytapy +xm +vlgfqoyzdczqbbaxjwbjjevjhxgopuqvqcrj +vpjqfbdnsdxlbuuiqocvrhap +mgumjbvnnzgnrdru +gcgzugazxdcamrhczfzhtmdjj +uislwq +vooai +zjuqfmebuzsqngzekyajujkopvayxtdzvugwwucvlsbrnhitfotmhhmgddlzlvqrkcponictrfweuilfjiuoabkfdvpjiqjrrgi +aptjfhmrnxaq +hbs +w +mwmoxqvucwygunplzvxtxpk +fgmqmtlorfzytjdzffsosfccnfwugrsrynuej +rpmpenrhsxoefnblyumjqwvuyszyppnttuyvazjdug +zdzxraxkroknkmqgvuoqeqdtvclsvvuwmdwzfugcpteohlogxubyoebvrzbqzklvehfcqadtdrkpubfhmokzwyosogepwragcpwxo +ax +dz +de + +thvkdmnbdws + +ejmubw +umvwkaubzurf +wyxtxeluaoox +wwbioobtgmkebxo +miglgnafmdarzkeblyjctuayzyoeqnfnbtrcbymdzkzg +loavxq +kzhllgsenxlbgdbfzwbg +yxflogzsohlcycbyzegeubfflouvtuatixhjvicjegltjiy +jigqfjppafdiarc +mcnmwtachgearonfcymvjbrnljjxmlzkudvzqsarnfysmxlfrtlvjxwvpdbhvwysnvcdozfcruhjwnucdzakkilmlfgjiolcatpfusm + +n +pdjunfcz +dc +edxkkxabsbvmvifiinnoccki +bc +gwtwsvorwzfqpz +exidmexstfflkhi +s +s +c +wtcjfywlayhpbqktcepoybowtkrmnumqsg +ozclkgjdmdk +jmegtbunyexurvfexhqptnqzie +tkoenpagzwqfawlxvzaijsjqhmg +swodqfjpdqcbkc +ujokogocyaygdibgpglecis +shlmdmgonvpuaxlhrymkxtiytmv +brhk +jmsyiuomiywxhegilycjprkyfgojdo + +wzdzrgpdiosdsvkcw +odlnmsfnjrcsnflviwvawybpczdkzvdocpwrmavz +p +ubowamlskcqhdxuckrxa +fawhntiwhmdwkddnahmtajqqazpdygttqivhdiodkcpcwv +gmxujmmaufmbipaiulhurzkfdg +eixjhmbaeoybiwk +kumntgrgiofcmujlzbcopuobambsw +mnjkqiyb +iktwnsnv +hfuzcl +tqiyqvagbqgtowpjbedgjot +dfemvamelxadkztogliizdtsddoboafawficudlefo +raecmxiiibljryswntpfed +mbwrtsebkeegw +x +epp +he + +vnztrswhiusokqdkmsnpuswucvfhcthjbtam +baxlwidsgbdpzvnlj +tcbjjoadrzo +aiidahyllzzsg + +igebuubweicbssgddpmqxunrawavuglmpxrtkqsvjjtscibqiejjfgfnovokodmqcqitlteiakooupvzkwucucrfdzjvjbqbkgutoybmpfvhbutigdxhfiqfplyciz +cnrhbjdnjftwfwlwzrdkwhajgsizsi +qfntnt +okqyfnbresp +asyg +mjqdkdyggdxzwuzglays +h +ifaqcazoy +fol +vvsusbnugduxsceozmsarbp +epjwtorx +bwiuxxiyc +cw +bwogruhctwkfvbexjnwircykxyzjmats +kygiochfwlpsvmxcgmtjrgvfdptd +q +qmpqe + +z +jghffhqfoecmszunhxmzmzhlmbrvjabhrkihgjmvckhkfpaygjkg + +kfiyfgounmhlvhupswqdgws +ezzdpyqucqoocsdcjtruqpokldfkmjhqzoynirybsifyaxnaxppthjoqy +nwetlgzwrhkhtuubbkbepuhbllxspvagxrqokwnrhkbwdwtp +hlazomrhqogoaxypqaszwfxxmutvbpuuvpdffuqskcbzlwyzcssnflkwiydoveyxjnzllzhyozbsa +hwnitkwbxcyibbqsluuqywbk + +ozpfjsdrc +yoepefuy +lvmspzepnetra +genbrcrmuqfvkaouvuymoxhcxotjjhk +pcshyqgbmqdubsdajnyfqvxkqvywffzn +ukhcbyzwslqeq +otfrmcbnhbyffxqregqoufdxucjunwdhlqqeiiawbxlpqeyzzopfungrryqdykgizrhqodirvazm +dhpfhzyq +cloz +eduupqifolfekve +qiec +ishnjukvomntmdthlkajxpiwk +y +axl +tmyskjqkjsvumizlal +wvvolwewsfxhhdieuagdcuhwsgqvswpbkdkpxskloalmr +ryfmhe +z +mmbpgsyrfvzdatbjrjhuipwt +llzwizmmuulgwocowwmugtaoewkhnqxparvtynlffffdfcocdbba + +pyczkzbmcgrdnxnmezsx +gsqe +mcocxcolcynhpecstsn +opnpplkccobjuhtbhirpzfxuktmpsiwbvsgiaavvdge +wpaldxzasnrbvtugjwytvtfttrh +zxecurevkjiyxy +wtnovebcmglkktic +fdpwfgvlvovxrwh +bmwgdullzy +uzwhagxinwqifxjbcntqzqoxkmpqxhe +jrfizsnwxwnnhb +inapddlahrp + +ndtvkceobe +buskgghihdjmjlwfc +j +rkvffxwtmzoeruhlsurwtnuh +cbvkhfepkdishfpqvijzrpleuy +jzdpxjhcgqnybssfegvrnpgyehdqpgjwudbwrjbavp +xzzvgqdrdwajmdmj +vfatwsxvwfdbdhnijdujoyotwvwjipuuetichcfmvgrsnjpqaaezjtkvc +lbfoqgfshrtwgdqufwnfuitdrjydqctqixlzufkdbp +zgau +qefdpmtkecvtj +kuphldkvnzdtpd +dti +fpd +gfrliyegxsb +i +qsddsrmkyfgzrjeqnitmnypbcakh +vfbvbrpuogzhzrbmklvhji +nkz +xlufbaoblbmeub +alwuzxzmobwdukvwnkiwmuqhuxfhevogdnqtmxjptqznrk +cngpoty + +ms +qvenfg +dmeaffm +jycfgnanbmoamhmarkmjcagbp +ysqmbhopgx +jczbzgwedsp + +zxzwjrxcwdtleizjlvifjwgxiibezwxhtzywqdi +mtgnlu +xboxirdchurkfnklnpkapnqfxnhrxyseiujrznjm + +zm +atddskbghcahlhql +szshwzmmvu +befdtpouamwhiisyybispkchpjhownatawjfbx + +ennkzbrlygd +zbt +upphzpdwzmlhhhbqvjsfmbnrar +ddcs +ipbxgzyudjyongtcyygncojdufnufqpdppgvq +gc +isu +foa +wf +jdlvqxgfbowhohhyyngbcs +zjuwjyucdwblatsnywaaoftlcamfbcnw +lzrioesuhoeevczuwrnltmkahfwiu +uicggfbddqltnjyxfltbnaekncnyxsit +zkxsqkqrwrzrxgxbsgxatybfr + +ptvmfyxdcglbfipcguqthjygzqnpqssscukzawynidtchjrrxwuxifoe +w +ohu +vg +zagpowezvbniybgold +lhqseqcxteiqtgnpanpvrmvvlltxh +mtfnxn +wyodtg + +rawpbgtpbaktqzmmpzxmrlwpvvmdsl +widcfbirvswraukbmkhf +vplrueuxomjkqrtjgyxjdkexttzyozawyq +hrpbahllznvmjudzxpbbv +tlavfrxygjfipkupwnbacltcfepeg +icu +otxcu +aewazy +hl + +fmrp +qaacthwzohenzjr +xbyebba +rvkph +mkhhmh +swme +zjmdoypaktglcyzobquunvthcdwegtbywpijxd +jvkuhnxqc +gibhqgjojsxt +bodbktzomiqujtbstqiyquwvqgufphqstenxvddkvtdh +bpusrxkfi +zgp +pmxvgamydyakituvvsucsuidrlznupcsinltmrahulhepxmhoqtfvpjkxzhrrinncuh +jzgkjjhjqykzelaszvcwvvwbnzsxdeaerfnaravk +ynanrqyrxo +zsmuxofullob +brklgrcqefdyoczy +qkpls +snhqumae +iqdtzjadzzvnqvdvjfsaf +nfqfdqiramueblxkaqxbbkxwywzgdbndjjiqk +tc +kp +cpuckbjsxhtxmomfesgxdpz +oseif +ybhxbvyxrpkrexrhjzoaxxohrhsniewsrktjnaztn +ggelspdzhzbchruhbjbjidgjwdlhdycetqaswh +jkgivsngygkbqtlmoj +dwpnanfvitxg +ospxbwxp +wgvmvrnjescemdoiralbkvemalifxnyhrbdgodml +hjtsnkzknkplbzsiwmneefdkihnhsamjsrxggclyjqgpqltizi + + +sykgbuypwwhweab +nvdkkkskmtiwpoerkon +sx +sbyflwwiqylbskdlxesmylpaz +dnwcjenaluwesyywfaezznwkdwpoesxpu +kie +dslccwfryol +gfhomgfn +zprjtfqvkotktzidmoyrivall +bunvsqkysdelozemnjoeqfolruulpbipm +ullyzfahpkhkja +hwd +kvyqtprpuulgsk +zotbkcadnxmfvqmtlbxalhughceyfcibtzzj +vvpjbgxygl +hpic +mhrqd +dv +thehuzdbaacoidjoljbysnqwrrxxplrdznmgiukkvjqbopb +moszjt +rmtbunktkywqirveeqfa +kse +wbfflnatgzobjrxghjgvcsyxoruenxhyomutbptswjajawqjpqafpdcstkiyjuilimecgejpqmyciolgcmdpcstzdozbmnza diff --git a/aho-corasick-0.6.4/ctags.rust b/aho-corasick-0.6.4/ctags.rust new file mode 100644 index 000000000..b42edf757 --- /dev/null +++ b/aho-corasick-0.6.4/ctags.rust @@ -0,0 +1,11 @@ +--langdef=Rust +--langmap=Rust:.rs +--regex-Rust=/^[ \t]*(#\[[^\]]\][ \t]*)*(pub[ \t]+)?(extern[ \t]+)?("[^"]+"[ \t]+)?(unsafe[ \t]+)?fn[ \t]+([a-zA-Z0-9_]+)/\6/f,functions,function definitions/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?type[ \t]+([a-zA-Z0-9_]+)/\2/T,types,type definitions/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?enum[ \t]+([a-zA-Z0-9_]+)/\2/g,enum,enumeration names/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?struct[ \t]+([a-zA-Z0-9_]+)/\2/s,structure names/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?mod[ \t]+([a-zA-Z0-9_]+)/\2/m,modules,module names/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?static[ \t]+([a-zA-Z0-9_]+)/\2/c,consts,static constants/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?trait[ \t]+([a-zA-Z0-9_]+)/\2/t,traits,traits/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?impl([ \t\n]+<.*>)?[ \t]+([a-zA-Z0-9_]+)/\3/i,impls,trait implementations/ +--regex-Rust=/^[ \t]*macro_rules![ \t]+([a-zA-Z0-9_]+)/\1/d,macros,macro definitions/ diff --git a/aho-corasick-0.6.4/examples/dict-search.rs b/aho-corasick-0.6.4/examples/dict-search.rs new file mode 100644 index 000000000..e4cb28854 --- /dev/null +++ b/aho-corasick-0.6.4/examples/dict-search.rs @@ -0,0 +1,151 @@ +// This example demonstrates how to use the Aho-Corasick algorithm to rapidly +// scan text for matches in a large dictionary of keywords. This example by +// default reads your system's dictionary (~120,000 words). +extern crate aho_corasick; +extern crate csv; +extern crate docopt; +extern crate memmap; +extern crate rustc_serialize; + +use std::error::Error; +use std::fs::File; +use std::io::{self, BufRead, Write}; +use std::process; + +use aho_corasick::{Automaton, AcAutomaton, Match}; +use docopt::Docopt; +use memmap::{Mmap, Protection}; + +static USAGE: &'static str = " +Usage: dict-search [options] + dict-search --help + +Options: + -d , --dict Path to dictionary of keywords to search. + [default: /usr/share/dict/words] + -m , --min-len The minimum length for a keyword in UTF-8 + encoded bytes. [default: 5] + --overlapping Report overlapping matches. + -c, --count Show only the numebr of matches. + --memory-usage Show memory usage of automaton. + --full Use fully expanded transition matrix. + Warning: may use lots of memory. + -h, --help Show this usage message. +"; + +#[derive(Clone, Debug, RustcDecodable)] +struct Args { + arg_input: String, + flag_dict: String, + flag_min_len: usize, + flag_overlapping: bool, + flag_memory_usage: bool, + flag_full: bool, + flag_count: bool, +} + +fn main() { + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.decode()) + .unwrap_or_else(|e| e.exit()); + match run(&args) { + Ok(()) => {} + Err(err) => { + writeln!(&mut io::stderr(), "{}", err).unwrap(); + process::exit(1); + } + } +} + +fn run(args: &Args) -> Result<(), Box> { + let aut = try!(build_automaton(&args.flag_dict, args.flag_min_len)); + if args.flag_memory_usage { + let (bytes, states) = if args.flag_full { + let aut = aut.into_full(); + (aut.heap_bytes(), aut.num_states()) + } else { + (aut.heap_bytes(), aut.num_states()) + }; + println!("{} bytes, {} states", bytes, states); + return Ok(()); + } + + if args.flag_full { + let aut = aut.into_full(); + if args.flag_overlapping { + if args.flag_count { + let mmap = Mmap::open_path( + &args.arg_input, Protection::Read).unwrap(); + let text = unsafe { mmap.as_slice() }; + println!("{}", aut.find_overlapping(text).count()); + } else { + let rdr = try!(File::open(&args.arg_input)); + try!(write_matches(&aut, aut.stream_find_overlapping(rdr))); + } + } else { + if args.flag_count { + let mmap = Mmap::open_path( + &args.arg_input, Protection::Read).unwrap(); + let text = unsafe { mmap.as_slice() }; + println!("{}", aut.find(text).count()); + } else { + let rdr = try!(File::open(&args.arg_input)); + try!(write_matches(&aut, aut.stream_find(rdr))); + } + } + } else { + if args.flag_overlapping { + if args.flag_count { + let mmap = Mmap::open_path( + &args.arg_input, Protection::Read).unwrap(); + let text = unsafe { mmap.as_slice() }; + println!("{}", aut.find_overlapping(text).count()); + } else { + let rdr = try!(File::open(&args.arg_input)); + try!(write_matches(&aut, aut.stream_find_overlapping(rdr))); + } + } else { + if args.flag_count { + let mmap = Mmap::open_path( + &args.arg_input, Protection::Read).unwrap(); + let text = unsafe { mmap.as_slice() }; + println!("{}", aut.find(text).count()); + } else { + let rdr = try!(File::open(&args.arg_input)); + try!(write_matches(&aut, aut.stream_find(rdr))); + } + } + } + Ok(()) +} + +fn write_matches(aut: &A, it: I) -> Result<(), Box> + where A: Automaton, I: Iterator> { + let mut wtr = csv::Writer::from_writer(io::stdout()); + try!(wtr.write(["pattern", "start", "end"].iter())); + for m in it { + let m = try!(m); + try!(wtr.write([ + aut.pattern(m.pati), + &m.start.to_string(), + &m.end.to_string(), + ].iter())); + } + try!(wtr.flush()); + Ok(()) +} + +fn build_automaton( + dict_path: &str, + min_len: usize, +) -> Result, Box> { + let buf = io::BufReader::new(try!(File::open(dict_path))); + let mut lines = Vec::with_capacity(1 << 10); + for line in buf.lines() { + let line = try!(line); + if line.len() >= min_len { + lines.push(line); + } + } + Ok(AcAutomaton::with_transitions(lines)) +} diff --git a/aho-corasick-0.6.4/session.vim b/aho-corasick-0.6.4/session.vim new file mode 100644 index 000000000..213c95660 --- /dev/null +++ b/aho-corasick-0.6.4/session.vim @@ -0,0 +1 @@ +au BufWritePost *.rs silent!make ctags > /dev/null 2>&1 diff --git a/aho-corasick-0.6.4/src/autiter.rs b/aho-corasick-0.6.4/src/autiter.rs new file mode 100644 index 000000000..21a02a4cf --- /dev/null +++ b/aho-corasick-0.6.4/src/autiter.rs @@ -0,0 +1,530 @@ +use std::io::{self, BufRead}; +use std::marker::PhantomData; + +use memchr::{memchr, memchr2, memchr3}; + +use super::{ROOT_STATE, StateIdx}; + +/// An abstraction over automatons and their corresponding iterators. +/// The type parameter `P` is the type of the pattern that was used to +/// construct this Automaton. +pub trait Automaton

{ + /// Return the next state given the current state and next character. + fn next_state(&self, si: StateIdx, b: u8) -> StateIdx; + + /// Return true if and only if the given state and current pattern index + /// indicate a match. + fn has_match(&self, si: StateIdx, outi: usize) -> bool; + + /// Build a match given the current state, pattern index and input index. + fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match; + + /// Return the set of bytes that have transitions in the root state. + fn start_bytes(&self) -> &[u8]; + + /// Returns all of the patterns matched by this automaton. + /// + /// The order of the patterns is the order in which they were added. + fn patterns(&self) -> &[P]; + + /// Returns the pattern indexed at `i`. + /// + /// The index corresponds to the position at which the pattern was added + /// to the automaton, starting at `0`. + fn pattern(&self, i: usize) -> &P; + + /// Return the number of patterns in the automaton. + #[inline] + fn len(&self) -> usize { + self.patterns().len() + } + + /// Returns true if the automaton has no patterns. + #[inline] + fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns an iterator of non-overlapping matches in `s`. + fn find<'a, 's, Q: ?Sized + AsRef<[u8]>>( + &'a self, + s: &'s Q, + ) -> Matches<'a, 's, P, Self> + where Self: Sized { + Matches { + aut: self, + text: s.as_ref(), + texti: 0, + si: ROOT_STATE, + _m: PhantomData, + } + } + + /// Returns an iterator of overlapping matches in `s`. + fn find_overlapping<'a, 's, Q: ?Sized + AsRef<[u8]>>( + &'a self, + s: &'s Q, + ) -> MatchesOverlapping<'a, 's, P, Self> + where Self: Sized { + MatchesOverlapping { + aut: self, + text: s.as_ref(), + texti: 0, + si: ROOT_STATE, + outi: 0, + _m: PhantomData, + } + } + + /// Returns an iterator of non-overlapping matches in the given reader. + fn stream_find<'a, R: io::Read>( + &'a self, + rdr: R, + ) -> StreamMatches<'a, R, P, Self> + where Self: Sized { + StreamMatches { + aut: self, + buf: io::BufReader::new(rdr), + texti: 0, + si: ROOT_STATE, + _m: PhantomData, + } + } + + /// Returns an iterator of overlapping matches in the given reader. + fn stream_find_overlapping<'a, R: io::Read>( + &'a self, + rdr: R, + ) -> StreamMatchesOverlapping<'a, R, P, Self> + where Self: Sized { + StreamMatchesOverlapping { + aut: self, + buf: io::BufReader::new(rdr), + texti: 0, + si: ROOT_STATE, + outi: 0, + _m: PhantomData, + } + } +} + +impl<'a, P: AsRef<[u8]>, A: 'a + Automaton

+ ?Sized> + Automaton

for &'a A { + fn next_state(&self, si: StateIdx, b: u8) -> StateIdx { + (**self).next_state(si, b) + } + + fn has_match(&self, si: StateIdx, outi: usize) -> bool { + (**self).has_match(si, outi) + } + + fn start_bytes(&self) -> &[u8] { + (**self).start_bytes() + } + + fn patterns(&self) -> &[P] { + (**self).patterns() + } + + fn pattern(&self, i: usize) -> &P { + (**self).pattern(i) + } + + fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match { + (**self).get_match(si, outi, texti) + } +} + +/// Records a match in the search text. +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Match { + /// The pattern index. + /// + /// This corresponds to the ordering in which the matched pattern was + /// added to the automaton, starting at `0`. + pub pati: usize, + /// The starting byte offset of the match in the search text. + pub start: usize, + /// The ending byte offset of the match in the search text. + /// + /// (This can be re-captiulated with `pati` and adding the pattern's + /// length to `start`, but it is convenient to have it here.) + pub end: usize, +} + +/// An iterator of non-overlapping matches for in-memory text. +/// +/// This iterator yields `Match` values. +/// +/// `'a` is the lifetime of the automaton, `'s` is the lifetime of the +/// search text, and `P` is the type of the Automaton's pattern. +#[derive(Debug)] +pub struct Matches<'a, 's, P, A: 'a + Automaton

+ ?Sized> { + aut: &'a A, + text: &'s [u8], + texti: usize, + si: StateIdx, + _m: PhantomData

, +} + +// When there's an initial lone start byte, it is usually worth it +// to use `memchr` to skip along the input. The problem is that +// the skipping function is called in the inner match loop, which +// can be quite costly if the skipping condition is never met. +// Therefore, we lift the case analysis outside of the inner loop at +// the cost of repeating code. +// +// `step_to_match` is the version of the inner loop without skipping, +// and `skip_to_match` is the version with skipping. +#[inline(never)] +fn step_to_match + ?Sized>( + aut: &A, + text: &[u8], + mut texti: usize, + mut si: StateIdx +) -> Option<(usize, StateIdx)> { + while texti < text.len() { + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + if texti + 4 < text.len() { + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + } + } + None +} + +fn skip_to_match + ?Sized, F: Fn(&A, &[u8], usize) -> usize>( + aut: &A, + text: &[u8], + mut texti: usize, + mut si: StateIdx, + skip: F, +) -> Option<(usize, StateIdx)> { + if si == ROOT_STATE { + texti = skip(aut, text, texti); + } + while texti < text.len() { + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + if si == ROOT_STATE { + texti = skip(aut, text, texti + 1); + } else { + texti += 1; + if texti + 4 < text.len() { + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + si = aut.next_state(si, text[texti]); + if aut.has_match(si, 0) { + return Some((texti, si)); + } + texti += 1; + } + } + } + None +} + +#[inline] +fn skip1 + ?Sized>( + aut: &A, + text: &[u8], + at: usize, +) -> usize { + debug_assert!(aut.start_bytes().len() == 1); + let b = aut.start_bytes()[0]; + match memchr(b, &text[at..]) { + None => text.len(), + Some(i) => at + i, + } +} + +#[inline] +fn skip2 + ?Sized>( + aut: &A, + text: &[u8], + at: usize, +) -> usize { + debug_assert!(aut.start_bytes().len() == 2); + let (b1, b2) = (aut.start_bytes()[0], aut.start_bytes()[1]); + match memchr2(b1, b2, &text[at..]) { + None => text.len(), + Some(i) => at + i, + } +} + +#[inline] +fn skip3 + ?Sized>( + aut: &A, + text: &[u8], + at: usize, +) -> usize { + debug_assert!(aut.start_bytes().len() == 3); + let (b1, b2, b3) = ( + aut.start_bytes()[0], aut.start_bytes()[1], aut.start_bytes()[2], + ); + match memchr3(b1, b2, b3, &text[at..]) { + None => text.len(), + Some(i) => at + i, + } +} + +impl<'a, 's, P, A: Automaton

+ ?Sized> Iterator for Matches<'a, 's, P, A> { + type Item = Match; + + fn next(&mut self) -> Option { + if self.aut.start_bytes().len() == 1 { + let skip = skip_to_match( + self.aut, self.text, self.texti, self.si, skip1); + if let Some((texti, si)) = skip { + self.texti = texti + 1; + self.si = ROOT_STATE; + return Some(self.aut.get_match(si, 0, texti)); + } + } else if self.aut.start_bytes().len() == 2 { + let skip = skip_to_match( + self.aut, self.text, self.texti, self.si, skip2); + if let Some((texti, si)) = skip { + self.texti = texti + 1; + self.si = ROOT_STATE; + return Some(self.aut.get_match(si, 0, texti)); + } + } else if self.aut.start_bytes().len() == 3 { + let skip = skip_to_match( + self.aut, self.text, self.texti, self.si, skip3); + if let Some((texti, si)) = skip { + self.texti = texti + 1; + self.si = ROOT_STATE; + return Some(self.aut.get_match(si, 0, texti)); + } + } else { + let step = step_to_match(self.aut, self.text, self.texti, self.si); + if let Some((texti, si)) = step { + self.texti = texti + 1; + self.si = ROOT_STATE; + return Some(self.aut.get_match(si, 0, texti)); + } + } + None + } +} + +/// An iterator of non-overlapping matches for streaming text. +/// +/// This iterator yields `io::Result` values. +/// +/// `'a` is the lifetime of the automaton, `R` is the type of the underlying +/// `io::Read`er, and P is the type of the Automaton's pattern. +#[derive(Debug)] +pub struct StreamMatches<'a, R, P, A: 'a + Automaton

+ ?Sized> { + aut: &'a A, + buf: io::BufReader, + texti: usize, + si: StateIdx, + _m: PhantomData

, +} + +impl<'a, R: io::Read, P, A: Automaton

> + Iterator for StreamMatches<'a, R, P, A> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + let mut m = None; + let mut consumed = 0; +'LOOP: loop { + self.buf.consume(consumed); + let bs = match self.buf.fill_buf() { + Err(err) => return Some(Err(err)), + Ok(bs) if bs.len() == 0 => break, + Ok(bs) => bs, + }; + consumed = bs.len(); // is shortened if we find a match + for (i, &b) in bs.iter().enumerate() { + self.si = self.aut.next_state(self.si, b); + if self.aut.has_match(self.si, 0) { + m = Some(Ok(self.aut.get_match(self.si, 0, self.texti))); + consumed = i + 1; + self.texti += 1; + self.si = ROOT_STATE; + break 'LOOP; + } + self.texti += 1; + } + } + self.buf.consume(consumed); + m + } +} + +/// An iterator of overlapping matches for in-memory text. +/// +/// This iterator yields `Match` values. +/// +/// `'a` is the lifetime of the automaton, `'s` is the lifetime of the +/// search text, and `P` is the type of the Automaton's pattern. +#[derive(Debug)] +pub struct MatchesOverlapping<'a, 's, P, A: 'a + Automaton

+ ?Sized> { + aut: &'a A, + text: &'s [u8], + texti: usize, + si: StateIdx, + outi: usize, + _m: PhantomData

, +} + +impl<'a, 's, P, A: Automaton

+ ?Sized> + Iterator for MatchesOverlapping<'a, 's, P, A> { + type Item = Match; + + fn next(&mut self) -> Option { + if self.aut.has_match(self.si, self.outi) { + let m = self.aut.get_match(self.si, self.outi, self.texti); + self.outi += 1; + if !self.aut.has_match(self.si, self.outi) { + self.texti += 1; + } + return Some(m); + } + + self.outi = 0; + if self.aut.start_bytes().len() == 1 { + let skip = skip_to_match( + self.aut, self.text, self.texti, self.si, skip1); + if let Some((texti, si)) = skip { + self.texti = texti; + self.si = si; + return self.next(); + } + } else if self.aut.start_bytes().len() == 2 { + let skip = skip_to_match( + self.aut, self.text, self.texti, self.si, skip2); + if let Some((texti, si)) = skip { + self.texti = texti; + self.si = si; + return self.next(); + } + } else if self.aut.start_bytes().len() == 3 { + let skip = skip_to_match( + self.aut, self.text, self.texti, self.si, skip3); + if let Some((texti, si)) = skip { + self.texti = texti; + self.si = si; + return self.next(); + } + } else { + let step = step_to_match(self.aut, self.text, self.texti, self.si); + if let Some((texti, si)) = step { + self.texti = texti; + self.si = si; + return self.next(); + } + } + None + } +} + +/// An iterator of overlapping matches for streaming text. +/// +/// This iterator yields `io::Result` values. +/// +/// `'a` is the lifetime of the automaton, `R` is the type of the underlying +/// `io::Read`er, and P is the type of the Automaton's pattern. +#[derive(Debug)] +pub struct StreamMatchesOverlapping<'a, R, P, A: 'a + Automaton

+ ?Sized> { + aut: &'a A, + buf: io::BufReader, + texti: usize, + si: StateIdx, + outi: usize, + _m: PhantomData

, +} + +impl<'a, R: io::Read, P, A: Automaton

+ ?Sized> + Iterator for StreamMatchesOverlapping<'a, R, P, A> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + if self.aut.has_match(self.si, self.outi) { + let m = self.aut.get_match(self.si, self.outi, self.texti); + self.outi += 1; + if !self.aut.has_match(self.si, self.outi) { + self.texti += 1; + } + return Some(Ok(m)); + } + let mut m = None; + let mut consumed = 0; + self.outi = 0; +'LOOP: loop { + self.buf.consume(consumed); + let bs = match self.buf.fill_buf() { + Err(err) => return Some(Err(err)), + Ok(bs) if bs.len() == 0 => break, + Ok(bs) => bs, + }; + consumed = bs.len(); // is shortened if we find a match + for (i, &b) in bs.iter().enumerate() { + self.si = self.aut.next_state(self.si, b); + if self.aut.has_match(self.si, self.outi) { + m = Some(Ok(self.aut.get_match( + self.si, self.outi, self.texti))); + consumed = i + 1; + self.outi += 1; + if !self.aut.has_match(self.si, self.outi) { + self.texti += 1; + } + break 'LOOP; + } + self.texti += 1; + } + } + self.buf.consume(consumed); + m + } +} diff --git a/aho-corasick-0.6.4/src/full.rs b/aho-corasick-0.6.4/src/full.rs new file mode 100644 index 000000000..f7d7c637e --- /dev/null +++ b/aho-corasick-0.6.4/src/full.rs @@ -0,0 +1,136 @@ +use std::fmt; +use std::mem; + +use super::{ + FAIL_STATE, + StateIdx, AcAutomaton, Transitions, Match, + usize_bytes, vec_bytes, +}; +use super::autiter::Automaton; + +/// A complete Aho-Corasick automaton. +/// +/// This uses a single transition matrix that permits each input character +/// to move to the next state with a single lookup in the matrix. +/// +/// This is as fast as it gets, but it is guaranteed to use a lot of memory. +/// Namely, it will use at least `4 * 256 * #states`, where the number of +/// states is capped at length of all patterns concatenated. +#[derive(Clone)] +pub struct FullAcAutomaton

{ + pats: Vec

, + trans: Vec, // row-major, where states are rows + out: Vec>, // indexed by StateIdx + start_bytes: Vec, +} + +impl> FullAcAutomaton

{ + /// Build a new expanded Aho-Corasick automaton from an existing + /// Aho-Corasick automaton. + pub fn new(ac: AcAutomaton) -> FullAcAutomaton

{ + let mut fac = FullAcAutomaton { + pats: vec![], + trans: vec![FAIL_STATE; 256 * ac.states.len()], + out: vec![vec![]; ac.states.len()], + start_bytes: vec![], + }; + fac.build_matrix(&ac); + fac.pats = ac.pats; + fac.start_bytes = ac.start_bytes; + fac + } + + #[doc(hidden)] + pub fn memory_usage(&self) -> usize { + self.pats.iter() + .map(|p| vec_bytes() + p.as_ref().len()) + .fold(0, |a, b| a + b) + + (4 * self.trans.len()) + + self.out.iter() + .map(|v| vec_bytes() + (usize_bytes() * v.len())) + .fold(0, |a, b| a + b) + + self.start_bytes.len() + } + + #[doc(hidden)] + pub fn heap_bytes(&self) -> usize { + self.pats.iter() + .map(|p| mem::size_of::

() + p.as_ref().len()) + .fold(0, |a, b| a + b) + + (4 * self.trans.len()) + + self.out.iter() + .map(|v| vec_bytes() + (usize_bytes() * v.len())) + .fold(0, |a, b| a + b) + + self.start_bytes.len() + } + + fn set(&mut self, si: StateIdx, i: u8, goto: StateIdx) { + let ns = self.num_states(); + self.trans[i as usize * ns + si as usize] = goto; + } + + #[doc(hidden)] + #[inline] + pub fn num_states(&self) -> usize { + self.out.len() + } +} + +impl> Automaton

for FullAcAutomaton

{ + #[inline] + fn next_state(&self, si: StateIdx, i: u8) -> StateIdx { + let at = i as usize * self.num_states() + si as usize; + unsafe { *self.trans.get_unchecked(at) } + } + + #[inline] + fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match { + let pati = self.out[si as usize][outi]; + let patlen = self.pats[pati].as_ref().len(); + let start = texti + 1 - patlen; + Match { + pati: pati, + start: start, + end: start + patlen, + } + } + + #[inline] + fn has_match(&self, si: StateIdx, outi: usize) -> bool { + unsafe { outi < self.out.get_unchecked(si as usize).len() } + } + + #[inline] + fn start_bytes(&self) -> &[u8] { + &self.start_bytes + } + + #[inline] + fn patterns(&self) -> &[P] { + &self.pats + } + + #[inline] + fn pattern(&self, i: usize) -> &P { + &self.pats[i] + } +} + +impl> FullAcAutomaton

{ + fn build_matrix(&mut self, ac: &AcAutomaton) { + for (si, s) in ac.states.iter().enumerate().skip(1) { + for b in (0..256).map(|b| b as u8) { + self.set(si as StateIdx, b, ac.next_state(si as StateIdx, b)); + } + for &pati in &s.out { + self.out[si].push(pati); + } + } + } +} + +impl + fmt::Debug> fmt::Debug for FullAcAutomaton

{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "FullAcAutomaton({:?})", self.pats) + } +} diff --git a/aho-corasick-0.6.4/src/lib.rs b/aho-corasick-0.6.4/src/lib.rs new file mode 100644 index 000000000..95ab071f6 --- /dev/null +++ b/aho-corasick-0.6.4/src/lib.rs @@ -0,0 +1,925 @@ +/*! +An implementation of the +[Aho-Corasick string search algorithm](https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_string_matching_algorithm). + +The Aho-Corasick algorithm is principally useful when you need to search many +large texts for a fixed (possibly large) set of keywords. In particular, the +Aho-Corasick algorithm preprocesses the set of keywords by constructing a +finite state machine. The search phase is then a quick linear scan through the +text. Each character in the search text causes a state transition in the +automaton. Matches are reported when the automaton enters a match state. + +# Examples + +The main type exposed by this crate is `AcAutomaton`, which can be constructed +from an iterator of pattern strings: + +```rust +use aho_corasick::{Automaton, AcAutomaton}; + +let aut = AcAutomaton::new(vec!["apple", "maple"]); + +// AcAutomaton also implements `FromIterator`: +let aut: AcAutomaton<&str> = ["apple", "maple"].iter().cloned().collect(); +``` + +Finding matches can be done with `find`: + +```rust +use aho_corasick::{Automaton, AcAutomaton, Match}; + +let aut = AcAutomaton::new(vec!["apple", "maple"]); +let mut it = aut.find("I like maple apples."); +assert_eq!(it.next(), Some(Match { + pati: 1, + start: 7, + end: 12, +})); +assert_eq!(it.next(), Some(Match { + pati: 0, + start: 13, + end: 18, +})); +assert_eq!(it.next(), None); +``` + +Use `find_overlapping` if you want to report all matches, even if they +overlap with each other. + +```rust +use aho_corasick::{Automaton, AcAutomaton, Match}; + +let aut = AcAutomaton::new(vec!["abc", "a"]); +let matches: Vec<_> = aut.find_overlapping("abc").collect(); +assert_eq!(matches, vec![ + Match { pati: 1, start: 0, end: 1}, Match { pati: 0, start: 0, end: 3 }, +]); + +// Regular `find` will report only one match: +let matches: Vec<_> = aut.find("abc").collect(); +assert_eq!(matches, vec![Match { pati: 1, start: 0, end: 1}]); +``` + +Finally, there are also methods for finding matches on *streams*. Namely, the +search text does not have to live in memory. It's useful to run this on files +that can't fit into memory: + +```no_run +use std::fs::File; + +use aho_corasick::{Automaton, AcAutomaton}; + +let aut = AcAutomaton::new(vec!["foo", "bar", "baz"]); +let rdr = File::open("search.txt").unwrap(); +for m in aut.stream_find(rdr) { + let m = m.unwrap(); // could be an IO error + println!("Pattern '{}' matched at: ({}, {})", + aut.pattern(m.pati), m.start, m.end); +} +``` + +There is also `stream_find_overlapping`, which is just like `find_overlapping`, +but it operates on streams. + +Please see `dict-search.rs` in this crate's `examples` directory for a more +complete example. It creates a large automaton from a dictionary and can do a +streaming match over arbitrarily large data. + +# Memory usage + +A key aspect of an Aho-Corasick implementation is how the state transitions +are represented. The easiest way to make the automaton fast is to store a +sparse 256-slot map in each state. It maps an input byte to a state index. +This makes the matching loop extremely fast, since it translates to a simple +pointer read. + +The problem is that as the automaton accumulates more states, you end up paying +a `256 * 4` (`4` is for the `u32` state index) byte penalty for every state +regardless of how many transitions it has. + +To solve this, only states near the root of the automaton have this sparse +map representation. States near the leaves of the automaton use a dense mapping +that requires a linear scan. + +(The specific limit currently set is `3`, so that states with a depth less than +or equal to `3` are less memory efficient. The result is that the memory usage +of the automaton stops growing rapidly past ~60MB, even for automatons with +thousands of patterns.) + +If you'd like to opt for the less-memory-efficient-but-faster version, then +you can construct an `AcAutomaton` with a `Sparse` transition strategy: + +```rust +use aho_corasick::{Automaton, AcAutomaton, Match, Sparse}; + +let aut = AcAutomaton::<&str, Sparse>::with_transitions(vec!["abc", "a"]); +let matches: Vec<_> = aut.find("abc").collect(); +assert_eq!(matches, vec![Match { pati: 1, start: 0, end: 1}]); +``` +*/ + +#![deny(missing_docs)] + +extern crate memchr; +#[cfg(test)] extern crate quickcheck; +#[cfg(test)] extern crate rand; + +use std::collections::VecDeque; +use std::fmt; +use std::iter::FromIterator; +use std::mem; + +pub use self::autiter::{ + Automaton, Match, + Matches, MatchesOverlapping, StreamMatches, StreamMatchesOverlapping, +}; +pub use self::full::FullAcAutomaton; + +// We're specifying paths explicitly so that we can use +// these modules simultaneously from `main.rs`. +// Should probably make just make `main.rs` a separate crate. +#[path = "autiter.rs"] +mod autiter; +#[path = "full.rs"] +mod full; + +/// The integer type used for the state index. +/// +/// Limiting this to 32 bit integers can have a big impact on memory usage +/// when using the `Sparse` transition representation. +pub type StateIdx = u32; + +// Constants for special state indexes. +const FAIL_STATE: u32 = 0; +const ROOT_STATE: u32 = 1; + +// Limit the depth at which we use a sparse alphabet map. Once the limit is +// reached, a dense set is used (and lookup becomes O(n)). +// +// This does have a performance hit, but the (straight forward) alternative +// is to have a `256 * 4` byte overhead for every state. +// Given that Aho-Corasick is typically used for dictionary searching, this +// can lead to dramatic memory bloat. +// +// This limit should only be increased at your peril. Namely, in the worst +// case, `256^DENSE_DEPTH_THRESHOLD * 4` corresponds to the memory usage in +// bytes. A value of `1` gives us a good balance. This is also a happy point +// in the benchmarks. A value of `0` gives considerably worse times on certain +// benchmarks (e.g., `ac_ten_one_prefix_byte_every_match`) than even a value +// of `1`. A value of `2` is slightly better than `1` and it looks like gains +// level off at that point with not much observable difference when set to +// `3`. +// +// Why not make this user configurable? Well, it doesn't make much sense +// because we pay for it with case analysis in the matching loop. Increasing it +// doesn't have much impact on performance (outside of pathological cases?). +// +// N.B. Someone else seems to have discovered an alternative, but I haven't +// grokked it yet: https://github.com/mischasan/aho-corasick +const DENSE_DEPTH_THRESHOLD: u32 = 1; + +/// An Aho-Corasick finite automaton. +/// +/// The type parameter `P` is the type of the pattern that was used to +/// construct this AcAutomaton. +#[derive(Clone)] +pub struct AcAutomaton { + pats: Vec

, + states: Vec>, + start_bytes: Vec, +} + +#[derive(Clone)] +struct State { + out: Vec, + fail: StateIdx, + goto: T, + depth: u32, +} + +impl> AcAutomaton

{ + /// Create a new automaton from an iterator of patterns. + /// + /// The patterns must be convertible to bytes (`&[u8]`) via the `AsRef` + /// trait. + pub fn new(pats: I) -> AcAutomaton + where I: IntoIterator { + AcAutomaton::with_transitions(pats) + } +} + +impl, T: Transitions> AcAutomaton { + /// Create a new automaton from an iterator of patterns. + /// + /// This constructor allows one to choose the transition representation. + /// + /// The patterns must be convertible to bytes (`&[u8]`) via the `AsRef` + /// trait. + pub fn with_transitions(pats: I) -> AcAutomaton + where I: IntoIterator { + AcAutomaton { + pats: vec![], // filled in later, avoid wrath of borrow checker + states: vec![State::new(0), State::new(0)], // empty and root + start_bytes: vec![], // also filled in later + }.build(pats.into_iter().collect()) + } + + /// Build out the entire automaton into a single matrix. + /// + /// This will make searching as fast as possible at the expense of using + /// at least `4 * 256 * #states` bytes of memory. + pub fn into_full(self) -> FullAcAutomaton

{ + FullAcAutomaton::new(self) + } + + #[doc(hidden)] + pub fn num_states(&self) -> usize { + self.states.len() + } + + #[doc(hidden)] + pub fn heap_bytes(&self) -> usize { + self.pats.iter() + .map(|p| mem::size_of::

() + p.as_ref().len()) + .fold(0, |a, b| a + b) + + self.states.iter() + .map(|s| mem::size_of::>() + s.heap_bytes()) + .fold(0, |a, b| a + b) + + self.start_bytes.len() + } +} + +impl, T: Transitions> Automaton

for AcAutomaton { + #[inline] + fn next_state(&self, mut si: StateIdx, b: u8) -> StateIdx { + loop { + let maybe_si = self.states[si as usize].goto(b); + if maybe_si != FAIL_STATE { + si = maybe_si; + break; + } else { + si = self.states[si as usize].fail; + } + } + si + } + + #[inline] + fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match { + let pati = self.states[si as usize].out[outi]; + let patlen = self.pats[pati].as_ref().len(); + let start = texti + 1 - patlen; + Match { + pati: pati, + start: start, + end: start + patlen, + } + } + + #[inline] + fn has_match(&self, si: StateIdx, outi: usize) -> bool { + outi < self.states[si as usize].out.len() + } + + #[inline] + fn start_bytes(&self) -> &[u8] { + &self.start_bytes + } + + #[inline] + fn patterns(&self) -> &[P] { + &self.pats + } + + #[inline] + fn pattern(&self, i: usize) -> &P { + &self.pats[i] + } +} + +// Below contains code for *building* the automaton. It's a reasonably faithful +// translation of the description/psuedo-code from: +// http://www.cs.uku.fi/~kilpelai/BSA05/lectures/slides04.pdf + +impl, T: Transitions> AcAutomaton { + // This is the first phase and builds the initial keyword tree. + fn build(mut self, pats: Vec

) -> AcAutomaton { + for (pati, pat) in pats.iter().enumerate() { + if pat.as_ref().is_empty() { + continue; + } + let mut previ = ROOT_STATE; + for &b in pat.as_ref() { + if self.states[previ as usize].goto(b) != FAIL_STATE { + previ = self.states[previ as usize].goto(b); + } else { + let depth = self.states[previ as usize].depth + 1; + let nexti = self.add_state(State::new(depth)); + self.states[previ as usize].set_goto(b, nexti); + previ = nexti; + } + } + self.states[previ as usize].out.push(pati); + } + for c in (0..256).into_iter().map(|c| c as u8) { + if self.states[ROOT_STATE as usize].goto(c) == FAIL_STATE { + self.states[ROOT_STATE as usize].set_goto(c, ROOT_STATE); + } else { + self.start_bytes.push(c); + } + } + // If any of the start bytes are non-ASCII, then remove them all, + // because we don't want to be calling memchr on non-ASCII bytes. + // (Well, we could, but it requires being more clever. Simply using + // the prefix byte isn't good enough.) + if self.start_bytes.iter().any(|&b| b > 0x7F) { + self.start_bytes.clear(); + } + self.pats = pats; + self.fill() + } + + // The second phase that fills in the back links. + fn fill(mut self) -> AcAutomaton { + // Fill up the queue with all non-root transitions out of the root + // node. Then proceed by breadth first traversal. + let mut q = VecDeque::new(); + for c in (0..256).into_iter().map(|c| c as u8) { + let si = self.states[ROOT_STATE as usize].goto(c); + if si != ROOT_STATE { + q.push_front(si); + } + } + while let Some(si) = q.pop_back() { + for c in (0..256).into_iter().map(|c| c as u8) { + let u = self.states[si as usize].goto(c); + if u != FAIL_STATE { + q.push_front(u); + let mut v = self.states[si as usize].fail; + while self.states[v as usize].goto(c) == FAIL_STATE { + v = self.states[v as usize].fail; + } + let ufail = self.states[v as usize].goto(c); + self.states[u as usize].fail = ufail; + let ufail_out = self.states[ufail as usize].out.clone(); + self.states[u as usize].out.extend(ufail_out); + } + } + } + self + } + + fn add_state(&mut self, state: State) -> StateIdx { + let i = self.states.len(); + self.states.push(state); + i as StateIdx + } +} + +impl State { + fn new(depth: u32) -> State { + State { + out: vec![], + fail: 1, + goto: Transitions::new(depth), + depth: depth, + } + } + + fn goto(&self, b: u8) -> StateIdx { + self.goto.goto(b) + } + + fn set_goto(&mut self, b: u8, si: StateIdx) { + self.goto.set_goto(b, si); + } + + fn heap_bytes(&self) -> usize { + (self.out.len() * usize_bytes()) + + self.goto.heap_bytes() + } +} + +/// An abstraction over state transition strategies. +/// +/// This is an attempt to let the caller choose the space/time trade offs +/// used for state transitions. +/// +/// (It's possible that this interface is merely good enough for just the two +/// implementations in this crate.) +pub trait Transitions { + /// Return a new state at the given depth. + fn new(depth: u32) -> Self; + /// Return the next state index given the next character. + fn goto(&self, alpha: u8) -> StateIdx; + /// Set the next state index for the character given. + fn set_goto(&mut self, alpha: u8, si: StateIdx); + /// The memory use in bytes (on the heap) of this set of transitions. + fn heap_bytes(&self) -> usize; +} + +/// State transitions that can be stored either sparsely or densely. +/// +/// This uses less space but at the expense of slower matching. +#[derive(Clone, Debug)] +pub struct Dense(DenseChoice); + +#[derive(Clone, Debug)] +enum DenseChoice { + Sparse(Vec), // indexed by alphabet + Dense(Vec<(u8, StateIdx)>), +} + +impl Transitions for Dense { + fn new(depth: u32) -> Dense { + if depth <= DENSE_DEPTH_THRESHOLD { + Dense(DenseChoice::Sparse(vec![0; 256])) + } else { + Dense(DenseChoice::Dense(vec![])) + } + } + + fn goto(&self, b1: u8) -> StateIdx { + match self.0 { + DenseChoice::Sparse(ref m) => m[b1 as usize], + DenseChoice::Dense(ref m) => { + for &(b2, si) in m { + if b1 == b2 { + return si; + } + } + FAIL_STATE + } + } + } + + fn set_goto(&mut self, b: u8, si: StateIdx) { + match self.0 { + DenseChoice::Sparse(ref mut m) => m[b as usize] = si, + DenseChoice::Dense(ref mut m) => m.push((b, si)), + } + } + + fn heap_bytes(&self) -> usize { + match self.0 { + DenseChoice::Sparse(ref m) => m.len() * 4, + DenseChoice::Dense(ref m) => m.len() * (1 + 4), + } + } +} + +/// State transitions that are always sparse. +/// +/// This can use enormous amounts of memory when there are many patterns, +/// but matching is very fast. +#[derive(Clone, Debug)] +pub struct Sparse(Vec); + +impl Transitions for Sparse { + fn new(_: u32) -> Sparse { + Sparse(vec![0; 256]) + } + + #[inline] + fn goto(&self, b: u8) -> StateIdx { + self.0[b as usize] + } + + fn set_goto(&mut self, b: u8, si: StateIdx) { + self.0[b as usize] = si; + } + + fn heap_bytes(&self) -> usize { + self.0.len() * 4 + } +} + +impl> FromIterator for AcAutomaton { + /// Create an automaton from an iterator of strings. + fn from_iter(it: T) -> AcAutomaton where T: IntoIterator { + AcAutomaton::new(it) + } +} + +// Provide some question debug impls for viewing automatons. +// The custom impls mostly exist for special showing of sparse maps. + +impl + fmt::Debug, T: Transitions> + fmt::Debug for AcAutomaton { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use std::iter::repeat; + + try!(writeln!(f, "{}", repeat('-').take(79).collect::())); + try!(writeln!(f, "Patterns: {:?}", self.pats)); + for (i, state) in self.states.iter().enumerate().skip(1) { + try!(writeln!(f, "{:3}: {}", i, state.debug(i == 1))); + } + write!(f, "{}", repeat('-').take(79).collect::()) + } +} + +impl State { + fn debug(&self, root: bool) -> String { + format!("State {{ depth: {:?}, out: {:?}, fail: {:?}, goto: {{{}}} }}", + self.depth, self.out, self.fail, self.goto_string(root)) + } + + fn goto_string(&self, root: bool) -> String { + use std::char::from_u32; + + let mut goto = vec![]; + for b in (0..256).map(|b| b as u8) { + let si = self.goto(b); + if (!root && si == FAIL_STATE) || (root && si == ROOT_STATE) { + continue; + } + goto.push(format!("{} => {}", from_u32(b as u32).unwrap(), si)); + } + goto.join(", ") + } +} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.debug(false)) + } +} + +impl AcAutomaton { + #[doc(hidden)] + pub fn dot(&self) -> String { + use std::fmt::Write; + let mut out = String::new(); + macro_rules! w { + ($w:expr, $($tt:tt)*) => { {write!($w, $($tt)*)}.unwrap() } + } + + w!(out, r#" +digraph automaton {{ + label=<{}>; + labelloc="l"; + labeljust="l"; + rankdir="LR"; +"#, self.pats.join(", ")); + for (i, s) in self.states.iter().enumerate().skip(1) { + let i = i as u32; + if s.out.len() == 0 { + w!(out, " {};\n", i); + } else { + w!(out, " {} [peripheries=2];\n", i); + } + w!(out, " {} -> {} [style=dashed];\n", i, s.fail); + for b in (0..256).map(|b| b as u8) { + let si = s.goto(b); + if si == FAIL_STATE || (i == ROOT_STATE && si == ROOT_STATE) { + continue; + } + w!(out, " {} -> {} [label={}];\n", i, si, b as char); + } + } + w!(out, "}}"); + out + } +} + +fn vec_bytes() -> usize { + usize_bytes() * 3 +} + +fn usize_bytes() -> usize { + let bits = usize::max_value().count_ones() as usize; + bits / 8 +} + +#[cfg(test)] +mod tests { + use std::collections::HashSet; + use std::io; + + use quickcheck::{Arbitrary, Gen, quickcheck}; + + use super::{Automaton, AcAutomaton, Match}; + + fn aut_find(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + AcAutomaton::new(xs.to_vec()).find(&haystack).collect() + } + + fn aut_finds(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + let cur = io::Cursor::new(haystack.as_bytes()); + AcAutomaton::new(xs.to_vec()) + .stream_find(cur).map(|r| r.unwrap()).collect() + } + + fn aut_findf(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + AcAutomaton::new(xs.to_vec()).into_full().find(haystack).collect() + } + + fn aut_findfs(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + let cur = io::Cursor::new(haystack.as_bytes()); + AcAutomaton::new(xs.to_vec()) + .into_full() + .stream_find(cur).map(|r| r.unwrap()).collect() + } + + fn aut_findo(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + AcAutomaton::new(xs.to_vec()).find_overlapping(haystack).collect() + } + + fn aut_findos(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + let cur = io::Cursor::new(haystack.as_bytes()); + AcAutomaton::new(xs.to_vec()) + .stream_find_overlapping(cur).map(|r| r.unwrap()).collect() + } + + fn aut_findfo(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + AcAutomaton::new(xs.to_vec()) + .into_full().find_overlapping(haystack).collect() + } + + fn aut_findfos(xs: &[S], haystack: &str) -> Vec + where S: Clone + AsRef<[u8]> { + let cur = io::Cursor::new(haystack.as_bytes()); + AcAutomaton::new(xs.to_vec()) + .into_full() + .stream_find_overlapping(cur).map(|r| r.unwrap()).collect() + } + + #[test] + fn one_pattern_one_match() { + let ns = vec!["a"]; + let hay = "za"; + let matches = vec![ + Match { pati: 0, start: 1, end: 2 }, + ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn one_pattern_many_match() { + let ns = vec!["a"]; + let hay = "zazazzzza"; + let matches = vec![ + Match { pati: 0, start: 1, end: 2 }, + Match { pati: 0, start: 3, end: 4 }, + Match { pati: 0, start: 8, end: 9 }, + ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn one_longer_pattern_one_match() { + let ns = vec!["abc"]; + let hay = "zazabcz"; + let matches = vec![ Match { pati: 0, start: 3, end: 6 } ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn one_longer_pattern_many_match() { + let ns = vec!["abc"]; + let hay = "zazabczzzzazzzabc"; + let matches = vec![ + Match { pati: 0, start: 3, end: 6 }, + Match { pati: 0, start: 14, end: 17 }, + ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn many_pattern_one_match() { + let ns = vec!["a", "b"]; + let hay = "zb"; + let matches = vec![ Match { pati: 1, start: 1, end: 2 } ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn many_pattern_many_match() { + let ns = vec!["a", "b"]; + let hay = "zbzazzzzb"; + let matches = vec![ + Match { pati: 1, start: 1, end: 2 }, + Match { pati: 0, start: 3, end: 4 }, + Match { pati: 1, start: 8, end: 9 }, + ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn many_longer_pattern_one_match() { + let ns = vec!["abc", "xyz"]; + let hay = "zazxyzz"; + let matches = vec![ Match { pati: 1, start: 3, end: 6 } ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn many_longer_pattern_many_match() { + let ns = vec!["abc", "xyz"]; + let hay = "zazxyzzzzzazzzabcxyz"; + let matches = vec![ + Match { pati: 1, start: 3, end: 6 }, + Match { pati: 0, start: 14, end: 17 }, + Match { pati: 1, start: 17, end: 20 }, + ]; + assert_eq!(&aut_find(&ns, hay), &matches); + assert_eq!(&aut_finds(&ns, hay), &matches); + assert_eq!(&aut_findf(&ns, hay), &matches); + assert_eq!(&aut_findfs(&ns, hay), &matches); + } + + #[test] + fn many_longer_pattern_overlap_one_match() { + let ns = vec!["abc", "bc"]; + let hay = "zazabcz"; + let matches = vec![ + Match { pati: 0, start: 3, end: 6 }, + Match { pati: 1, start: 4, end: 6 }, + ]; + assert_eq!(&aut_findo(&ns, hay), &matches); + assert_eq!(&aut_findos(&ns, hay), &matches); + assert_eq!(&aut_findfo(&ns, hay), &matches); + assert_eq!(&aut_findfos(&ns, hay), &matches); + } + + #[test] + fn many_longer_pattern_overlap_one_match_reverse() { + let ns = vec!["abc", "bc"]; + let hay = "xbc"; + let matches = vec![ Match { pati: 1, start: 1, end: 3 } ]; + assert_eq!(&aut_findo(&ns, hay), &matches); + assert_eq!(&aut_findos(&ns, hay), &matches); + assert_eq!(&aut_findfo(&ns, hay), &matches); + assert_eq!(&aut_findfos(&ns, hay), &matches); + } + + #[test] + fn many_longer_pattern_overlap_many_match() { + let ns = vec!["abc", "bc", "c"]; + let hay = "zzzabczzzbczzzc"; + let matches = vec![ + Match { pati: 0, start: 3, end: 6 }, + Match { pati: 1, start: 4, end: 6 }, + Match { pati: 2, start: 5, end: 6 }, + Match { pati: 1, start: 9, end: 11 }, + Match { pati: 2, start: 10, end: 11 }, + Match { pati: 2, start: 14, end: 15 }, + ]; + assert_eq!(&aut_findo(&ns, hay), &matches); + assert_eq!(&aut_findos(&ns, hay), &matches); + assert_eq!(&aut_findfo(&ns, hay), &matches); + assert_eq!(&aut_findfos(&ns, hay), &matches); + } + + #[test] + fn many_longer_pattern_overlap_many_match_reverse() { + let ns = vec!["abc", "bc", "c"]; + let hay = "zzzczzzbczzzabc"; + let matches = vec![ + Match { pati: 2, start: 3, end: 4 }, + Match { pati: 1, start: 7, end: 9 }, + Match { pati: 2, start: 8, end: 9 }, + Match { pati: 0, start: 12, end: 15 }, + Match { pati: 1, start: 13, end: 15 }, + Match { pati: 2, start: 14, end: 15 }, + ]; + assert_eq!(&aut_findo(&ns, hay), &matches); + assert_eq!(&aut_findos(&ns, hay), &matches); + assert_eq!(&aut_findfo(&ns, hay), &matches); + assert_eq!(&aut_findfos(&ns, hay), &matches); + } + + #[test] + fn pattern_returns_original_type() { + let aut = AcAutomaton::new(vec!["apple", "maple"]); + + // Explicitly given this type to assert that the thing returned + // from the function is our original type. + let pat: &str = aut.pattern(0); + assert_eq!(pat, "apple"); + + // Also check the return type of the `patterns` function. + let pats: &[&str] = aut.patterns(); + assert_eq!(pats, &["apple", "maple"]); + } + + // Quickcheck time. + + // This generates very small ascii strings, which makes them more likely + // to interact in interesting ways with larger haystack strings. + #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] + pub struct SmallAscii(String); + + impl Arbitrary for SmallAscii { + fn arbitrary(g: &mut G) -> SmallAscii { + use std::char::from_u32; + SmallAscii((0..2) + .map(|_| from_u32(g.gen_range(97, 123)).unwrap()) + .collect()) + } + + fn shrink(&self) -> Box> { + Box::new(self.0.shrink().map(SmallAscii)) + } + } + + impl From for String { + fn from(s: SmallAscii) -> String { s.0 } + } + + impl AsRef<[u8]> for SmallAscii { + fn as_ref(&self) -> &[u8] { self.0.as_ref() } + } + + // This is the same arbitrary impl as `String`, except it has a bias toward + // ASCII characters. + #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] + pub struct BiasAscii(String); + + impl Arbitrary for BiasAscii { + fn arbitrary(g: &mut G) -> BiasAscii { + use std::char::from_u32; + let size = { let s = g.size(); g.gen_range(0, s) }; + let mut s = String::with_capacity(size); + for _ in 0..size { + if g.gen_weighted_bool(3) { + s.push(char::arbitrary(g)); + } else { + for _ in 0..5 { + s.push(from_u32(g.gen_range(97, 123)).unwrap()); + } + } + } + BiasAscii(s) + } + + fn shrink(&self) -> Box> { + Box::new(self.0.shrink().map(BiasAscii)) + } + } + + fn naive_find(xs: &[S], haystack: &str) -> Vec + where S: Clone + Into { + let needles: Vec = + xs.to_vec().into_iter().map(Into::into).collect(); + let mut matches = vec![]; + for hi in 0..haystack.len() { + for (pati, needle) in needles.iter().enumerate() { + let needle = needle.as_bytes(); + if needle.len() == 0 || needle.len() > haystack.len() - hi { + continue; + } + if needle == &haystack.as_bytes()[hi..hi+needle.len()] { + matches.push(Match { + pati: pati, + start: hi, + end: hi + needle.len(), + }); + } + } + } + matches + } + + #[test] + fn qc_ac_equals_naive() { + fn prop(needles: Vec, haystack: BiasAscii) -> bool { + let aut_matches = aut_findo(&needles, &haystack.0); + let naive_matches = naive_find(&needles, &haystack.0); + // Ordering isn't always the same. I don't think we care, so do + // an unordered comparison. + let aset: HashSet = aut_matches.iter().cloned().collect(); + let nset: HashSet = naive_matches.iter().cloned().collect(); + aset == nset + } + quickcheck(prop as fn(Vec, BiasAscii) -> bool); + } +} diff --git a/aho-corasick-0.6.4/src/main.rs b/aho-corasick-0.6.4/src/main.rs new file mode 100644 index 000000000..60562ac6a --- /dev/null +++ b/aho-corasick-0.6.4/src/main.rs @@ -0,0 +1,13 @@ +extern crate memchr; + +use std::env; + +use lib::AcAutomaton; + +#[allow(dead_code)] +mod lib; + +fn main() { + let aut = AcAutomaton::new(env::args().skip(1)); + println!("{}", aut.dot().trim()); +} diff --git a/atty-0.2.6/.cargo-checksum.json b/atty-0.2.6/.cargo-checksum.json new file mode 100644 index 000000000..7cf20fcba --- /dev/null +++ b/atty-0.2.6/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859"} \ No newline at end of file diff --git a/atty-0.2.6/.travis.yml b/atty-0.2.6/.travis.yml new file mode 100644 index 000000000..a628724c9 --- /dev/null +++ b/atty-0.2.6/.travis.yml @@ -0,0 +1,73 @@ +sudo: false +language: rust +matrix: + fast_finish: true + include: + - rust: nightly + - rust: nightly + os: osx + - rust: beta + - rust: beta + os: osx + - rust: stable + - rust: stable + os: osx + allow_failures: + - rust: nightly + +before_cache: + # Travis can't cache files that are not readable by "others" + - chmod -R a+r $HOME/.cargo + +before_install: + # install kcov + - > + if [ ! -d "$HOME/.kcov/bin" ]; then + wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && + tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && + cmake -DCMAKE_INSTALL_PREFIX:PATH=$HOME/.kcov .. && make && make install && cd ../.. + fi + - export PATH=$HOME/.kcov/bin:$PATH + +script: + - cargo build + +cache: + cargo: true + apt: true + directories: + - target/debug/deps + - target/debug/build + +addons: + apt: + packages: + - libcurl4-openssl-dev + - libelf-dev + - libdw-dev + - binutils-dev + - libiberty-dev + +after_success: + - '[ $TRAVIS_RUST_VERSION = stable ] && + [ $TRAVIS_BRANCH = master ] && + [ $TRAVIS_PULL_REQUEST = false ] && + (ls target/debug && + RUSTFLAGS="-C link-dead-code" cargo test --no-run && + for file in target/debug/atty-*; do + if [[ "${file: -2}" != ".d" ]]; then + mkdir -p "target/cov/$(basename $file)"; + kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; + fi; + done && + kcov --coveralls-id=$COVERALLS_REPO_TOKEN --merge target/cov target/cov/* && + echo "covered") || true' + - '[ $TRAVIS_RUST_VERSION = stable ] && + [ $TRAVIS_BRANCH = master ] && + [ $TRAVIS_PULL_REQUEST = false ] + && cargo doc --no-deps && + echo "" > target/doc/index.html && + pip install --user ghp-import && + /home/travis/.local/bin/ghp-import -n target/doc && + git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages && + echo "documented"' \ No newline at end of file diff --git a/atty-0.2.6/CHANGELOG.md b/atty-0.2.6/CHANGELOG.md new file mode 100644 index 000000000..e25acdf44 --- /dev/null +++ b/atty-0.2.6/CHANGELOG.md @@ -0,0 +1,41 @@ +# 0.2.6 + +* updated winapi dependency to [0.3](https://retep998.github.io/blog/winapi-0.3/) [#18](https://github.com/softprops/atty/pull/18) + +# 0.2.5 + +* added support for Wasm compile targets [#17](https://github.com/softprops/atty/pull/17) + +# 0.2.4 + +* added support for Wasm compile targets [#17](https://github.com/softprops/atty/pull/17) + +# 0.2.3 + +* added support for Redox OS [#14](https://github.com/softprops/atty/pull/14) + +# 0.2.2 + +* use target specific dependencies [#11](https://github.com/softprops/atty/pull/11) +* Add tty detection for MSYS terminals [#12](https://github.com/softprops/atty/pull/12) + +# 0.2.1 + +* fix windows bug + +# 0.2.0 + +* support for various stream types + +# 0.1.2 + +* windows support (with automated testing) +* automated code coverage + +# 0.1.1 + +* bumped libc dep from `0.1` to `0.2` + +# 0.1.0 + +* initial release diff --git a/atty-0.2.6/Cargo.toml b/atty-0.2.6/Cargo.toml new file mode 100644 index 000000000..554a59e2b --- /dev/null +++ b/atty-0.2.6/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "atty" +version = "0.2.6" +authors = ["softprops "] +description = "A simple interface for querying atty" +homepage = "https://github.com/softprops/atty" +documentation = "http://softprops.github.io/atty" +readme = "README.md" +keywords = ["terminal", "tty"] +license = "MIT" +repository = "https://github.com/softprops/atty" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["consoleapi", "processenv", "minwinbase", "minwindef", "winbase"] +[target."cfg(unix)".dependencies.libc] +version = "0.2" +default-features = false +[target."cfg(target_os = \"redox\")".dependencies.termion] +version = "1.5" +[badges.travis-ci] +repository = "softprops/atty" diff --git a/atty-0.2.6/LICENSE b/atty-0.2.6/LICENSE new file mode 100644 index 000000000..d1f01c829 --- /dev/null +++ b/atty-0.2.6/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2015-2017 Doug Tangren + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/atty-0.2.6/README.md b/atty-0.2.6/README.md new file mode 100644 index 000000000..2ee7df42d --- /dev/null +++ b/atty-0.2.6/README.md @@ -0,0 +1,78 @@ +# atty + +[![Build Status](https://travis-ci.org/softprops/atty.svg?branch=master)](https://travis-ci.org/softprops/atty) [![Build status](https://ci.appveyor.com/api/projects/status/geggrsnsjsuse8cv?svg=true)](https://ci.appveyor.com/project/softprops/atty) [![Coverage Status](https://coveralls.io/repos/softprops/atty/badge.svg?branch=master&service=github)](https://coveralls.io/github/softprops/atty?branch=master) [![crates.io](http://meritbadge.herokuapp.com/atty)](https://crates.io/crates/atty) + +> are you or are you not a tty? + + +[Documentation](http://softprops.github.io/atty) + +## install + +Add the following to your `Cargo.toml` + +```toml +[dependencies] +atty = "0.2" +``` + +## usage + +```rust +extern crate atty; + +use atty::Stream; + +fn main() { + if atty::is(Stream::Stdout) { + println!("I'm a terminal"); + } else { + println!("I'm not"); + } +} +``` + +## testing + +This library has been unit tested on both unix and windows platforms (via appveyor). + + +A simple example program is provided in this repo to test various tty's. By default. + +It prints + +```bash +$ cargo run --example atty +stdout? true +stderr? true +stdin? true +``` + +To test std in, pipe some text to the program + +```bash +$ echo "test" | cargo run --example atty +stdout? true +stderr? true +stdin? false +``` + +To test std out, pipe the program to something + +```bash +$ cargo run --example atty | grep std +stdout? false +stderr? true +stdin? true +``` + +To test std err, pipe the program to something redirecting std err + +```bash +$ cargo run --example atty 2>&1 | grep std +stdout? false +stderr? false +stdin? true +``` + +Doug Tangren (softprops) 2015-2017 diff --git a/atty-0.2.6/appveyor.yml b/atty-0.2.6/appveyor.yml new file mode 100644 index 000000000..d7fb12794 --- /dev/null +++ b/atty-0.2.6/appveyor.yml @@ -0,0 +1,16 @@ +environment: + matrix: + - TARGET: nightly-x86_64-pc-windows-msvc + - TARGET: nightly-i686-pc-windows-msvc + - TARGET: nightly-x86_64-pc-windows-gnu + - TARGET: nightly-i686-pc-windows-gnu +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-${env:TARGET}.exe" -FileName "rust-install.exe" + - ps: .\rust-install.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null + - ps: $env:PATH="$env:PATH;C:\rust\bin" + - call "%VCVARS%" || ver>nul + - rustc -vV + - cargo -vV +build: false +test_script: + - cargo build diff --git a/atty-0.2.6/examples/atty.rs b/atty-0.2.6/examples/atty.rs new file mode 100644 index 000000000..3b3635e59 --- /dev/null +++ b/atty-0.2.6/examples/atty.rs @@ -0,0 +1,9 @@ +extern crate atty; + +use atty::{is, Stream}; + +fn main() { + println!("stdout? {}", is(Stream::Stdout)); + println!("stderr? {}", is(Stream::Stderr)); + println!("stdin? {}", is(Stream::Stdin)); +} diff --git a/atty-0.2.6/rustfmt.toml b/atty-0.2.6/rustfmt.toml new file mode 100644 index 000000000..d83987dca --- /dev/null +++ b/atty-0.2.6/rustfmt.toml @@ -0,0 +1,10 @@ +# keep imports tidy +reorder_imported_names = true +reorder_imports = true +reorder_imports_in_group = true +# there is no try! +use_try_shorthand = true +# don't create rustfmt artifacts +write_mode = "Replace" +# reduce wide load +max_width = 80 \ No newline at end of file diff --git a/atty-0.2.6/src/lib.rs b/atty-0.2.6/src/lib.rs new file mode 100644 index 000000000..379bd94a7 --- /dev/null +++ b/atty-0.2.6/src/lib.rs @@ -0,0 +1,210 @@ +//! atty is a simple utility that answers one question +//! > is this a tty? +//! +//! usage is just as simple +//! +//! ``` +//! if atty::is(atty::Stream::Stdout) { +//! println!("i'm a tty") +//! } +//! ``` +//! +//! ``` +//! if atty::isnt(atty::Stream::Stdout) { +//! println!("i'm not a tty") +//! } +//! ``` + +#![cfg_attr(unix, no_std)] + +#[cfg(unix)] +extern crate libc; +#[cfg(windows)] +extern crate winapi; +#[cfg(target_os = "redox")] +extern crate termion; + +#[cfg(windows)] +use winapi::shared::minwindef::DWORD; + +/// possible stream sources +#[derive(Clone, Copy, Debug)] +pub enum Stream { + Stdout, + Stderr, + Stdin, +} + +/// returns true if this is a tty +#[cfg(unix)] +pub fn is(stream: Stream) -> bool { + extern crate libc; + + let fd = match stream { + Stream::Stdout => libc::STDOUT_FILENO, + Stream::Stderr => libc::STDERR_FILENO, + Stream::Stdin => libc::STDIN_FILENO, + }; + unsafe { libc::isatty(fd) != 0 } +} + +/// returns true if this is a tty +#[cfg(windows)] +pub fn is(stream: Stream) -> bool { + use winapi::um::winbase::{STD_ERROR_HANDLE as STD_ERROR, STD_INPUT_HANDLE as STD_INPUT, + STD_OUTPUT_HANDLE as STD_OUTPUT}; + + let (fd, others) = match stream { + Stream::Stdin => (STD_INPUT, [STD_ERROR, STD_OUTPUT]), + Stream::Stderr => (STD_ERROR, [STD_INPUT, STD_OUTPUT]), + Stream::Stdout => (STD_OUTPUT, [STD_INPUT, STD_ERROR]), + }; + if unsafe { console_on_any(&[fd]) } { + // False positives aren't possible. If we got a console then + // we definitely have a tty on stdin. + return true; + } + + // At this point, we *could* have a false negative. We can determine that + // this is true negative if we can detect the presence of a console on + // any of the other streams. If another stream has a console, then we know + // we're in a Windows console and can therefore trust the negative. + if unsafe { console_on_any(&others) } { + return false; + } + + // Otherwise, we fall back to a very strange msys hack to see if we can + // sneakily detect the presence of a tty. + unsafe { msys_tty_on(fd) } +} + +/// returns true if this is _not_ a tty +pub fn isnt(stream: Stream) -> bool { + !is(stream) +} + +/// Returns true if any of the given fds are on a console. +#[cfg(windows)] +unsafe fn console_on_any(fds: &[DWORD]) -> bool { + use winapi::um::consoleapi::GetConsoleMode; + use winapi::um::processenv::GetStdHandle; + + for &fd in fds { + let mut out = 0; + let handle = GetStdHandle(fd); + if GetConsoleMode(handle, &mut out) != 0 { + return true; + } + } + false +} + +/// Returns true if there is an MSYS tty on the given handle. +#[cfg(windows)] +unsafe fn msys_tty_on(fd: DWORD) -> bool { + use std::ffi::OsString; + use std::mem; + use std::os::windows::ffi::OsStringExt; + use std::slice; + + use winapi::ctypes::c_void; + use winapi::um::winbase::GetFileInformationByHandleEx; + use winapi::um::fileapi::FILE_NAME_INFO; + use winapi::um::minwinbase::FileNameInfo; + use winapi::um::processenv::GetStdHandle; + use winapi::shared::minwindef::MAX_PATH; + + let size = mem::size_of::(); + let mut name_info_bytes = vec![0u8; size + MAX_PATH]; + let res = GetFileInformationByHandleEx( + GetStdHandle(fd), + FileNameInfo, + &mut *name_info_bytes as *mut _ as *mut c_void, + name_info_bytes.len() as u32, + ); + if res == 0 { + return true; + } + let name_info: FILE_NAME_INFO = *(name_info_bytes[0..size].as_ptr() as + *const FILE_NAME_INFO); + let name_bytes = + &name_info_bytes[size..size + name_info.FileNameLength as usize]; + let name_u16 = slice::from_raw_parts( + name_bytes.as_ptr() as *const u16, + name_bytes.len() / 2, + ); + let name = OsString::from_wide(name_u16) + .as_os_str() + .to_string_lossy() + .into_owned(); + name.contains("msys-") || name.contains("-pty") +} + +/// returns true if this is a tty +#[cfg(target_os = "redox")] +pub fn is(stream: Stream) -> bool { + use std::io; + use termion::is_tty; + + match stream { + Stream::Stdin => is_tty(&io::stdin()), + Stream::Stdout => is_tty(&io::stdout()), + Stream::Stderr => is_tty(&io::stderr()), + } +} + +/// returns true if this is a tty +#[cfg(target_arch = "wasm32")] +pub fn is(_stream: Stream) -> bool { + false +} + +#[cfg(test)] +mod tests { + use super::{Stream, is}; + + #[test] + #[cfg(windows)] + fn is_err() { + // appveyor pipes its output + assert!(!is(Stream::Stderr)) + } + + #[test] + #[cfg(windows)] + fn is_out() { + // appveyor pipes its output + assert!(!is(Stream::Stdout)) + } + + #[test] + #[cfg(windows)] + fn is_in() { + assert!(is(Stream::Stdin)) + } + + #[test] + #[cfg(unix)] + fn is_err() { + assert!(is(Stream::Stderr)) + } + + #[test] + #[cfg(unix)] + fn is_out() { + assert!(is(Stream::Stdout)) + } + + #[test] + #[cfg(target_os = "macos")] + fn is_in() { + // macos on travis seems to pipe its input + assert!(is(Stream::Stdin)) + } + + #[test] + #[cfg(all(not(target_os = "macos"), unix))] + fn is_in() { + assert!(is(Stream::Stdin)) + } +} diff --git a/backtrace-0.3.5/.cargo-checksum.json b/backtrace-0.3.5/.cargo-checksum.json new file mode 100644 index 000000000..9c12cca71 --- /dev/null +++ b/backtrace-0.3.5/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2"} \ No newline at end of file diff --git a/backtrace-0.3.5/.travis.yml b/backtrace-0.3.5/.travis.yml new file mode 100644 index 000000000..a0cfb6e14 --- /dev/null +++ b/backtrace-0.3.5/.travis.yml @@ -0,0 +1,60 @@ +language: rust +sudo: false + +matrix: + include: + - rust: 1.21.0 + - rust: stable + - os: osx + - rust: beta + - rust: nightly + + - rust: nightly + before_script: + - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH + script: + - cargo doc --no-deps --all-features + after_success: + - travis-cargo --only nightly doc-upload + +dist: trusty + +addons: + sources: + # Provides clang-3.9 + - llvm-toolchain-trusty-3.9 + apt: + packages: + # Required for `bindgen`, which is required by `findshlibs`, which is + # required by the `gimli` feature. + - clang-3.9 + +script: + - cargo test + - cargo test --no-default-features + - cargo test --no-default-features --features 'libunwind' + - cargo test --no-default-features --features 'libunwind dladdr' + - cargo test --no-default-features --features 'libunwind libbacktrace' + - cargo test --no-default-features --features 'unix-backtrace' + - cargo test --no-default-features --features 'unix-backtrace dladdr' + - cargo test --no-default-features --features 'unix-backtrace libbacktrace' + - cargo test --no-default-features --features 'serialize-serde' + - cargo test --no-default-features --features 'serialize-rustc' + - cargo test --no-default-features --features 'serialize-rustc serialize-serde' + - cargo test --no-default-features --features 'cpp_demangle' + - cargo test --no-default-features --features 'gimli-symbolize' + - cd ./cpp_smoke_test && cargo test && cd .. + - cargo clean && cargo build + +notifications: + email: + on_success: never + +after_success: + - travis-cargo --only nightly doc-upload + +env: + global: + # serde-codegen has historically needed a large stack to expand + - RUST_MIN_STACK=16777216 + - secure: "Kuf3j6gC3MhR+F7g8/5J4+3tu+FXJP/SqKjsUVVjs/qjniIVX3MwZPhtP/pVtdRvYjW0NzLw5Nufb4o1cyY4uKwR8BHHNuEUE/h3mPShjWHqzLyn5QiBumPozsFCa32H4gconRmp3+s0YrBT7nLoGvUZZS0dkldMkpvvrPL/yUKXLS8HEP4L1GO5iMQQYG6i3sbWTbHikE6ZQogW/iZommyqUkVB/s/SQvdH9SXu89ttNXlm/F+EIsgsgyzpbULp5sD34GRDPJe+H1m+sgA1kTRrzmuBGNmz9mx6GyIKaqACTm1gRcb06nFjTPVTQioJBNnoV7TEqZCvjuSsUjcGmP4Aeissafo93ADzV+bd0uoWIScE9ltSVS+RgCDV+sd0GHz5U6FjhgZp0amaVl3d6hPp8lbTfK/gfj1i9ktQfKZbG7rB4tfIU1KeQRkyE9vb/TaKp8nwBbc4SVQ4EKFOlRbE1S1FooaKZweW8w57d2u+sMMMVJbO28/Ap8tk9xDSOl4shPaT0iM0U9/heF8FmCZB1OKXLKn6TAaNFnaMTvdTHl+Tjrf6Vzd/oPXJ7GuaB6eLxXYjXvZHuKiLkSZriOzhL7PbijNILbSgZt7+Fa0vcnXP8zgD4dmupx/CoIHLN9NP4o9cGXuBcaJ/iFryJ4i5LKGFNEUHtXkavDrcgcA=" diff --git a/backtrace-0.3.5/Cargo.toml b/backtrace-0.3.5/Cargo.toml new file mode 100644 index 000000000..474c78bab --- /dev/null +++ b/backtrace-0.3.5/Cargo.toml @@ -0,0 +1,74 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "backtrace" +version = "0.3.5" +authors = ["Alex Crichton ", "The Rust Project Developers"] +description = "A library to acquire a stack trace (backtrace) at runtime in a Rust program.\n" +homepage = "https://github.com/alexcrichton/backtrace-rs" +documentation = "http://alexcrichton.com/backtrace-rs" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/backtrace-rs" +[dependencies.addr2line] +version = "0.5.0" +optional = true + +[dependencies.cfg-if] +version = "0.1" + +[dependencies.cpp_demangle] +version = "0.2.3" +optional = true +default-features = false + +[dependencies.findshlibs] +version = "0.3.3" +optional = true + +[dependencies.rustc-demangle] +version = "0.1.4" + +[dependencies.rustc-serialize] +version = "0.3" +optional = true + +[dependencies.serde] +version = "1.0" +optional = true + +[dependencies.serde_derive] +version = "1.0" +optional = true + +[features] +coresymbolication = [] +dbghelp = ["winapi"] +default = ["libunwind", "libbacktrace", "coresymbolication", "dladdr", "dbghelp"] +dladdr = [] +gimli-symbolize = ["addr2line", "findshlibs"] +kernel32 = [] +libbacktrace = ["backtrace-sys"] +libunwind = [] +serialize-rustc = ["rustc-serialize"] +serialize-serde = ["serde", "serde_derive"] +unix-backtrace = [] +[target."cfg(all(unix, not(target_os = \"fuchsia\"), not(target_os = \"emscripten\"), not(target_os = \"macos\"), not(target_os = \"ios\")))".dependencies.backtrace-sys] +version = "0.1.3" +optional = true +[target."cfg(unix)".dependencies.libc] +version = "0.2" +[target."cfg(windows)".dependencies.winapi] +version = "0.3.3" +features = ["std", "dbghelp", "processthreadsapi", "winnt", "minwindef"] +optional = true diff --git a/backtrace-0.3.5/LICENSE-APACHE b/backtrace-0.3.5/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/backtrace-0.3.5/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/backtrace-0.3.5/LICENSE-MIT b/backtrace-0.3.5/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/backtrace-0.3.5/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/backtrace-0.3.5/README.md b/backtrace-0.3.5/README.md new file mode 100644 index 000000000..f887f8c2c --- /dev/null +++ b/backtrace-0.3.5/README.md @@ -0,0 +1,91 @@ +# backtrace-rs + +[![Build Status](https://travis-ci.org/alexcrichton/backtrace-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/backtrace-rs) +[![Build status](https://ci.appveyor.com/api/projects/status/v4l9oj4aqbbgyx44?svg=true)](https://ci.appveyor.com/project/alexcrichton/backtrace-rs) + +[Documentation](http://alexcrichton.com/backtrace-rs) + +A library for acquiring backtraces at runtime for Rust. This library aims to +enhance the support given by the standard library at `std::rt` by providing a +more stable and programmatic interface. + +## Install + +```toml +[dependencies] +backtrace = "0.3" +``` + +```rust +extern crate backtrace; +``` + +Note that this crate requires `make`, `objcopy`, and `ar` to be present on Linux +systems. + +## Usage + +To simply capture a backtrace and defer dealing with it until a later time, +you can use the top-level `Backtrace` type. + +```rust +extern crate backtrace; + +use backtrace::Backtrace; + +fn main() { + let bt = Backtrace::new(); + + // do_some_work(); + + println!("{:?}", bt); +} +``` + +If, however, you'd like more raw access to the actual tracing functionality, you +can use the `trace` and `resolve` functions directly. + +```rust +extern crate backtrace; + +fn main() { + backtrace::trace(|frame| { + let ip = frame.ip(); + let symbol_address = frame.symbol_address(); + + // Resolve this instruction pointer to a symbol name + backtrace::resolve(ip, |symbol| { + if let Some(name) = symbol.name() { + // ... + } + if let Some(filename) = symbol.filename() { + // ... + } + }); + + true // keep going to the next frame + }); +} +``` + +## Platform Support + +This library currently supports OSX, Linux, and Windows. Support for other +platforms is always welcome! + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in backtrace-rs by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/backtrace-0.3.5/appveyor.yml b/backtrace-0.3.5/appveyor.yml new file mode 100644 index 000000000..43b83c769 --- /dev/null +++ b/backtrace-0.3.5/appveyor.yml @@ -0,0 +1,20 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-gnu + MSYS_BITS: 64 + - TARGET: i686-pc-windows-gnu + MSYS_BITS: 32 + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - set PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - if defined MSYS_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS_BITS%\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --target %TARGET% diff --git a/backtrace-0.3.5/examples/backtrace.rs b/backtrace-0.3.5/examples/backtrace.rs new file mode 100644 index 000000000..7f9042ed7 --- /dev/null +++ b/backtrace-0.3.5/examples/backtrace.rs @@ -0,0 +1,7 @@ +extern crate backtrace; + +use backtrace::Backtrace; + +fn main() { + println!("{:?}", Backtrace::new()); +} diff --git a/backtrace-0.3.5/examples/raw.rs b/backtrace-0.3.5/examples/raw.rs new file mode 100644 index 000000000..40a6b120a --- /dev/null +++ b/backtrace-0.3.5/examples/raw.rs @@ -0,0 +1,48 @@ +extern crate backtrace; + +fn main() { + foo(); +} + +fn foo() { bar() } +fn bar() { baz() } +fn baz() { print() } + +#[cfg(target_pointer_width = "32")] const HEX_WIDTH: usize = 10; +#[cfg(target_pointer_width = "64")] const HEX_WIDTH: usize = 20; + +fn print() { + let mut cnt = 0; + backtrace::trace(|frame| { + let ip = frame.ip(); + print!("frame #{:<2} - {:#02$x}", cnt, ip as usize, HEX_WIDTH); + cnt += 1; + + let mut resolved = false; + backtrace::resolve(frame.ip(), |symbol| { + if !resolved { + resolved = true; + } else { + print!("{}", vec![" "; 7 + 2 + 3 + HEX_WIDTH].join("")); + } + + if let Some(name) = symbol.name() { + print!(" - {}", name); + } else { + print!(" - "); + } + if let Some(file) = symbol.filename() { + if let Some(l) = symbol.lineno() { + print!("\n{:13}{:4$}@ {}:{}", "", "", file.display(), l, + HEX_WIDTH); + } + } + println!(""); + + }); + if !resolved { + println!(" - "); + } + true // keep going + }); +} diff --git a/backtrace-0.3.5/src/backtrace/dbghelp.rs b/backtrace-0.3.5/src/backtrace/dbghelp.rs new file mode 100644 index 000000000..26b395a69 --- /dev/null +++ b/backtrace-0.3.5/src/backtrace/dbghelp.rs @@ -0,0 +1,103 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] + +use std::mem; +use winapi::ctypes::*; +use winapi::shared::minwindef::*; +use winapi::um::processthreadsapi; +use winapi::um::winnt::{self, CONTEXT}; +use winapi::um::dbghelp; +use winapi::um::dbghelp::*; + +pub struct Frame { + inner: STACKFRAME64, +} + +impl Frame { + pub fn ip(&self) -> *mut c_void { + self.inner.AddrPC.Offset as *mut _ + } + + pub fn symbol_address(&self) -> *mut c_void { + self.ip() + } +} + +#[inline(always)] +pub fn trace(cb: &mut FnMut(&super::Frame) -> bool) { + // According to windows documentation, all dbghelp functions are + // single-threaded. + let _g = ::lock::lock(); + + unsafe { + // Allocate necessary structures for doing the stack walk + let process = processthreadsapi::GetCurrentProcess(); + let thread = processthreadsapi::GetCurrentThread(); + + // The CONTEXT structure needs to be aligned on a 16-byte boundary for + // 64-bit Windows, but currently we don't have a way to express that in + // Rust. Allocations are generally aligned to 16-bytes, though, so we + // box this up. + let mut context = Box::new(mem::zeroed::()); + winnt::RtlCaptureContext(&mut *context); + let mut frame = super::Frame { + inner: Frame { inner: mem::zeroed() }, + }; + let image = init_frame(&mut frame.inner.inner, &context); + + // Initialize this process's symbols + let _c = ::dbghelp_init(); + + // And now that we're done with all the setup, do the stack walking! + while dbghelp::StackWalk64(image as DWORD, + process, + thread, + &mut frame.inner.inner, + &mut *context as *mut _ as *mut _, + None, + Some(dbghelp::SymFunctionTableAccess64), + Some(dbghelp::SymGetModuleBase64), + None) == TRUE { + if frame.inner.inner.AddrPC.Offset == frame.inner.inner.AddrReturn.Offset || + frame.inner.inner.AddrPC.Offset == 0 || + frame.inner.inner.AddrReturn.Offset == 0 { + break + } + + if !cb(&frame) { + break + } + } + } +} + +#[cfg(target_arch = "x86_64")] +fn init_frame(frame: &mut STACKFRAME64, ctx: &CONTEXT) -> WORD { + frame.AddrPC.Offset = ctx.Rip as u64; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Offset = ctx.Rsp as u64; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Offset = ctx.Rbp as u64; + frame.AddrFrame.Mode = AddrModeFlat; + winnt::IMAGE_FILE_MACHINE_AMD64 +} + +#[cfg(target_arch = "x86")] +fn init_frame(frame: &mut STACKFRAME64, ctx: &CONTEXT) -> WORD { + frame.AddrPC.Offset = ctx.Eip as u64; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrStack.Offset = ctx.Esp as u64; + frame.AddrStack.Mode = AddrModeFlat; + frame.AddrFrame.Offset = ctx.Ebp as u64; + frame.AddrFrame.Mode = AddrModeFlat; + winnt::IMAGE_FILE_MACHINE_I386 +} diff --git a/backtrace-0.3.5/src/backtrace/libunwind.rs b/backtrace-0.3.5/src/backtrace/libunwind.rs new file mode 100644 index 000000000..4d7aef248 --- /dev/null +++ b/backtrace-0.3.5/src/backtrace/libunwind.rs @@ -0,0 +1,200 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::os::raw::c_void; + +pub struct Frame { + ctx: *mut uw::_Unwind_Context, +} + +impl Frame { + pub fn ip(&self) -> *mut c_void { + let mut ip_before_insn = 0; + let mut ip = unsafe { + uw::_Unwind_GetIPInfo(self.ctx, &mut ip_before_insn) as *mut c_void + }; + if !ip.is_null() && ip_before_insn == 0 { + // this is a non-signaling frame, so `ip` refers to the address + // after the calling instruction. account for that. + ip = (ip as usize - 1) as *mut _; + } + return ip + } + + pub fn symbol_address(&self) -> *mut c_void { + // dladdr() on osx gets whiny when we use FindEnclosingFunction, and + // it appears to work fine without it, so we only use + // FindEnclosingFunction on non-osx platforms. In doing so, we get a + // slightly more accurate stack trace in the process. + // + // This is often because panic involves the last instruction of a + // function being "call std::rt::begin_unwind", with no ret + // instructions after it. This means that the return instruction + // pointer points *outside* of the calling function, and by + // unwinding it we go back to the original function. + if cfg!(target_os = "macos") || cfg!(target_os = "ios") { + self.ip() + } else { + unsafe { uw::_Unwind_FindEnclosingFunction(self.ip()) } + } + } +} + +#[inline(always)] +pub fn trace(mut cb: &mut FnMut(&super::Frame) -> bool) { + unsafe { + uw::_Unwind_Backtrace(trace_fn, &mut cb as *mut _ as *mut _); + } + + extern fn trace_fn(ctx: *mut uw::_Unwind_Context, + arg: *mut c_void) -> uw::_Unwind_Reason_Code { + let cb = unsafe { &mut *(arg as *mut &mut FnMut(&super::Frame) -> bool) }; + let cx = super::Frame { + inner: Frame { ctx: ctx }, + }; + + let mut bomb = ::Bomb { enabled: true }; + let keep_going = cb(&cx); + bomb.enabled = false; + + if keep_going { + uw::_URC_NO_REASON + } else { + uw::_URC_FAILURE + } + } +} + +/// Unwind library interface used for backtraces +/// +/// Note that dead code is allowed as here are just bindings +/// iOS doesn't use all of them it but adding more +/// platform-specific configs pollutes the code too much +#[allow(non_camel_case_types)] +#[allow(non_snake_case)] +#[allow(dead_code)] +mod uw { + pub use self::_Unwind_Reason_Code::*; + + use libc; + use std::os::raw::{c_int, c_void}; + + #[repr(C)] + pub enum _Unwind_Reason_Code { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9, // used only by ARM EABI + } + + pub enum _Unwind_Context {} + + pub type _Unwind_Trace_Fn = + extern fn(ctx: *mut _Unwind_Context, + arg: *mut c_void) -> _Unwind_Reason_Code; + + extern { + // No native _Unwind_Backtrace on iOS + #[cfg(not(all(target_os = "ios", target_arch = "arm")))] + pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, + trace_argument: *mut c_void) + -> _Unwind_Reason_Code; + + // available since GCC 4.2.0, should be fine for our purpose + #[cfg(all(not(all(target_os = "android", target_arch = "arm")), + not(all(target_os = "linux", target_arch = "arm"))))] + pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, + ip_before_insn: *mut c_int) + -> libc::uintptr_t; + + #[cfg(all(not(target_os = "android"), + not(all(target_os = "linux", target_arch = "arm"))))] + pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) + -> *mut c_void; + } + + // On android, the function _Unwind_GetIP is a macro, and this is the + // expansion of the macro. This is all copy/pasted directly from the + // header file with the definition of _Unwind_GetIP. + #[cfg(any(all(target_os = "android", target_arch = "arm"), + all(target_os = "linux", target_arch = "arm")))] + pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t { + #[repr(C)] + enum _Unwind_VRS_Result { + _UVRSR_OK = 0, + _UVRSR_NOT_IMPLEMENTED = 1, + _UVRSR_FAILED = 2, + } + #[repr(C)] + enum _Unwind_VRS_RegClass { + _UVRSC_CORE = 0, + _UVRSC_VFP = 1, + _UVRSC_FPA = 2, + _UVRSC_WMMXD = 3, + _UVRSC_WMMXC = 4, + } + #[repr(C)] + enum _Unwind_VRS_DataRepresentation { + _UVRSD_UINT32 = 0, + _UVRSD_VFPX = 1, + _UVRSD_FPAX = 2, + _UVRSD_UINT64 = 3, + _UVRSD_FLOAT = 4, + _UVRSD_DOUBLE = 5, + } + + type _Unwind_Word = libc::c_uint; + extern { + fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context, + klass: _Unwind_VRS_RegClass, + word: _Unwind_Word, + repr: _Unwind_VRS_DataRepresentation, + data: *mut c_void) + -> _Unwind_VRS_Result; + } + + let mut val: _Unwind_Word = 0; + let ptr = &mut val as *mut _Unwind_Word; + let _ = _Unwind_VRS_Get(ctx, _Unwind_VRS_RegClass::_UVRSC_CORE, 15, + _Unwind_VRS_DataRepresentation::_UVRSD_UINT32, + ptr as *mut c_void); + (val & !1) as libc::uintptr_t + } + + // This function doesn't exist on Android or ARM/Linux, so make it same + // to _Unwind_GetIP + #[cfg(any(all(target_os = "android", target_arch = "arm"), + all(target_os = "linux", target_arch = "arm")))] + pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, + ip_before_insn: *mut c_int) + -> libc::uintptr_t + { + *ip_before_insn = 0; + _Unwind_GetIP(ctx) + } + + // This function also doesn't exist on Android or ARM/Linux, so make it + // a no-op + #[cfg(any(target_os = "android", + all(target_os = "linux", target_arch = "arm")))] + pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) + -> *mut c_void + { + pc + } +} + + diff --git a/backtrace-0.3.5/src/backtrace/mod.rs b/backtrace-0.3.5/src/backtrace/mod.rs new file mode 100644 index 000000000..53fe5b416 --- /dev/null +++ b/backtrace-0.3.5/src/backtrace/mod.rs @@ -0,0 +1,113 @@ +use std::fmt; + +use std::os::raw::c_void; + +/// Inspects the current call-stack, passing all active frames into the closure +/// provided to calculate a stack trace. +/// +/// This function is the workhorse of this library in calculating the stack +/// traces for a program. The given closure `cb` is yielded instances of a +/// `Frame` which represent information about that call frame on the stack. The +/// closure is yielded frames in a top-down fashion (most recently called +/// functions first). +/// +/// The closure's return value is an indication of whether the backtrace should +/// continue. A return value of `false` will terminate the backtrace and return +/// immediately. +/// +/// Once a `Frame` is acquired you will likely want to call `backtrace::resolve` +/// to convert the `ip` (instruction pointer) or symbol address to a `Symbol` +/// through which the name and/or filename/line number can be learned. +/// +/// Note that this is a relatively low-level function and if you'd like to, for +/// example, capture a backtrace to be inspected later, then the `Backtrace` +/// type may be more appropriate. +/// +/// # Example +/// +/// ``` +/// extern crate backtrace; +/// +/// fn main() { +/// backtrace::trace(|frame| { +/// // ... +/// +/// true // continue the backtrace +/// }); +/// } +/// ``` +#[inline(never)] // if this is never inlined then the first frame can be known + // to be skipped +pub fn trace bool>(mut cb: F) { + trace_imp(&mut cb) +} + +/// A trait representing one frame of a backtrace, yielded to the `trace` +/// function of this crate. +/// +/// The tracing function's closure will be yielded frames, and the frame is +/// virtually dispatched as the underlying implementation is not always known +/// until runtime. +pub struct Frame { + inner: FrameImp, +} + +impl Frame { + /// Returns the current instruction pointer of this frame. + /// + /// This is normally the next instruction to execute in the frame, but not + /// all implementations list this with 100% accuracy (but it's generally + /// pretty close). + /// + /// It is recommended to pass this value to `backtrace::resolve` to turn it + /// into a symbol name. + pub fn ip(&self) -> *mut c_void { + self.inner.ip() + } + + /// Returns the starting symbol address of the frame of this function. + /// + /// This will attempt to rewind the instruction pointer returned by `ip` to + /// the start of the function, returning that value. In some cases, however, + /// backends will just return `ip` from this function. + /// + /// The returned value can sometimes be used if `backtrace::resolve` failed + /// on the `ip` given above. + pub fn symbol_address(&self) -> *mut c_void { + self.inner.symbol_address() + } +} + +impl fmt::Debug for Frame { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Frame") + .field("ip", &self.ip()) + .field("symbol_address", &self.symbol_address()) + .finish() + } +} + +cfg_if! { + if #[cfg(all(unix, + not(target_os = "emscripten"), + not(all(target_os = "ios", target_arch = "arm")), + feature = "libunwind"))] { + mod libunwind; + use self::libunwind::trace as trace_imp; + use self::libunwind::Frame as FrameImp; + } else if #[cfg(all(unix, + not(target_os = "emscripten"), + feature = "unix-backtrace"))] { + mod unix_backtrace; + use self::unix_backtrace::trace as trace_imp; + use self::unix_backtrace::Frame as FrameImp; + } else if #[cfg(all(windows, feature = "dbghelp"))] { + mod dbghelp; + use self::dbghelp::trace as trace_imp; + use self::dbghelp::Frame as FrameImp; + } else { + mod noop; + use self::noop::trace as trace_imp; + use self::noop::Frame as FrameImp; + } +} diff --git a/backtrace-0.3.5/src/backtrace/noop.rs b/backtrace-0.3.5/src/backtrace/noop.rs new file mode 100644 index 000000000..8b8f8766e --- /dev/null +++ b/backtrace-0.3.5/src/backtrace/noop.rs @@ -0,0 +1,16 @@ +use std::os::raw::c_void; + +#[inline(always)] +pub fn trace(_cb: &mut FnMut(&super::Frame) -> bool) {} + +pub struct Frame; + +impl Frame { + pub fn ip(&self) -> *mut c_void { + 0 as *mut _ + } + + pub fn symbol_address(&self) -> *mut c_void { + 0 as *mut _ + } +} diff --git a/backtrace-0.3.5/src/backtrace/unix_backtrace.rs b/backtrace-0.3.5/src/backtrace/unix_backtrace.rs new file mode 100644 index 000000000..061bba9ef --- /dev/null +++ b/backtrace-0.3.5/src/backtrace/unix_backtrace.rs @@ -0,0 +1,46 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; +use std::os::raw::{c_void, c_int}; + +pub struct Frame { + addr: *mut c_void, +} + +impl Frame { + pub fn ip(&self) -> *mut c_void { self.addr } + pub fn symbol_address(&self) -> *mut c_void { self.addr } +} + +extern { + fn backtrace(buf: *mut *mut c_void, sz: c_int) -> c_int; +} + +#[inline(always)] +pub fn trace(cb: &mut FnMut(&super::Frame) -> bool) { + const SIZE: usize = 100; + + let mut buf: [*mut c_void; SIZE]; + let cnt; + unsafe { + buf = mem::zeroed(); + cnt = backtrace(buf.as_mut_ptr(), SIZE as c_int); + } + + for addr in buf[..cnt as usize].iter() { + let cx = super::Frame { + inner: Frame { addr: *addr }, + }; + if !cb(&cx) { + return + } + } +} diff --git a/backtrace-0.3.5/src/capture.rs b/backtrace-0.3.5/src/capture.rs new file mode 100644 index 000000000..570b117b0 --- /dev/null +++ b/backtrace-0.3.5/src/capture.rs @@ -0,0 +1,237 @@ +use std::fmt; +use std::mem; +use std::os::raw::c_void; +use std::path::{Path, PathBuf}; + +use {trace, resolve, SymbolName}; + +/// Representation of an owned and self-contained backtrace. +/// +/// This structure can be used to capture a backtrace at various points in a +/// program and later used to inspect what the backtrace was at that time. +#[derive(Clone)] +#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] +#[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))] +pub struct Backtrace { + frames: Vec, +} + +/// Captured version of a frame in a backtrace. +/// +/// This type is returned as a list from `Backtrace::frames` and represents one +/// stack frame in a captured backtrace. +#[derive(Clone)] +#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] +#[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))] +pub struct BacktraceFrame { + ip: usize, + symbol_address: usize, + symbols: Option>, +} + +/// Captured version of a symbol in a backtrace. +/// +/// This type is returned as a list from `BacktraceFrame::symbols` and +/// represents the metadata for a symbol in a backtrace. +#[derive(Clone)] +#[cfg_attr(feature = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] +#[cfg_attr(feature = "serialize-serde", derive(Deserialize, Serialize))] +pub struct BacktraceSymbol { + name: Option>, + addr: Option, + filename: Option, + lineno: Option, +} + +impl Backtrace { + /// Captures a backtrace at the callsite of this function, returning an + /// owned representation. + /// + /// This function is useful for representing a backtrace as an object in + /// Rust. This returned value can be sent across threads and printed + /// elsewhere, and the purpose of this value is to be entirely self + /// contained. + /// + /// # Examples + /// + /// ``` + /// use backtrace::Backtrace; + /// + /// let current_backtrace = Backtrace::new(); + /// ``` + pub fn new() -> Backtrace { + let mut bt = Backtrace::new_unresolved(); + bt.resolve(); + return bt + } + + /// Similar to `new` except that this does not resolve any symbols, this + /// simply captures the backtrace as a list of addresses. + /// + /// At a later time the `resolve` function can be called to resolve this + /// backtrace's symbols into readable names. This function exists because + /// the resolution process can sometimes take a significant amount of time + /// whereas any one backtrace may only be rarely printed. + /// + /// # Examples + /// + /// ``` + /// use backtrace::Backtrace; + /// + /// let mut current_backtrace = Backtrace::new_unresolved(); + /// println!("{:?}", current_backtrace); // no symbol names + /// current_backtrace.resolve(); + /// println!("{:?}", current_backtrace); // symbol names now present + /// ``` + pub fn new_unresolved() -> Backtrace { + let mut frames = Vec::new(); + trace(|frame| { + frames.push(BacktraceFrame { + ip: frame.ip() as usize, + symbol_address: frame.symbol_address() as usize, + symbols: None, + }); + true + }); + + Backtrace { frames: frames } + } + + /// Returns the frames from when this backtrace was captured. + /// + /// The first entry of this slice is likely the function `Backtrace::new`, + /// and the last frame is likely something about how this thread or the main + /// function started. + pub fn frames(&self) -> &[BacktraceFrame] { + &self.frames + } + + /// If this backtrace was created from `new_unresolved` then this function + /// will resolve all addresses in the backtrace to their symbolic names. + /// + /// If this backtrace has been previously resolved or was created through + /// `new`, this function does nothing. + pub fn resolve(&mut self) { + for frame in self.frames.iter_mut().filter(|f| f.symbols.is_none()) { + let mut symbols = Vec::new(); + resolve(frame.ip as *mut _, |symbol| { + symbols.push(BacktraceSymbol { + name: symbol.name().map(|m| m.as_bytes().to_vec()), + addr: symbol.addr().map(|a| a as usize), + filename: symbol.filename().map(|m| m.to_path_buf()), + lineno: symbol.lineno(), + }); + }); + frame.symbols = Some(symbols); + } + } +} + +impl From> for Backtrace { + fn from(frames: Vec) -> Self { + Backtrace { + frames: frames + } + } +} + +impl Into> for Backtrace { + fn into(self) -> Vec { + self.frames + } +} + +impl BacktraceFrame { + /// Same as `Frame::ip` + pub fn ip(&self) -> *mut c_void { + self.ip as *mut c_void + } + + /// Same as `Frame::symbol_address` + pub fn symbol_address(&self) -> *mut c_void { + self.symbol_address as *mut c_void + } + + /// Returns the list of symbols that this frame corresponds to. + /// + /// Normally there is only one symbol per frame, but sometimes if a number + /// of functions are inlined into one frame then multiple symbols will be + /// returned. The first symbol listed is the "innermost function", whereas + /// the last symbol is the outermost (last caller). + /// + /// Note that if this frame came from an unresolved backtrace then this will + /// return an empty list. + pub fn symbols(&self) -> &[BacktraceSymbol] { + self.symbols.as_ref().map(|s| &s[..]).unwrap_or(&[]) + } +} + +impl BacktraceSymbol { + /// Same as `Symbol::name` + pub fn name(&self) -> Option { + self.name.as_ref().map(|s| SymbolName::new(s)) + } + + /// Same as `Symbol::addr` + pub fn addr(&self) -> Option<*mut c_void> { + self.addr.map(|s| s as *mut c_void) + } + + /// Same as `Symbol::filename` + pub fn filename(&self) -> Option<&Path> { + self.filename.as_ref().map(|p| &**p) + } + + /// Same as `Symbol::lineno` + pub fn lineno(&self) -> Option { + self.lineno + } +} + +impl fmt::Debug for Backtrace { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let hex_width = mem::size_of::() * 2 + 2; + + try!(write!(fmt, "stack backtrace:")); + + for (idx, frame) in self.frames().iter().enumerate() { + let ip = frame.ip(); + try!(write!(fmt, "\n{:4}: {:2$?}", idx, ip, hex_width)); + + let symbols = match frame.symbols { + Some(ref s) => s, + None => { + try!(write!(fmt, " - ")); + continue + } + }; + if symbols.len() == 0 { + try!(write!(fmt, " - ")); + } + + for (idx, symbol) in symbols.iter().enumerate() { + if idx != 0 { + try!(write!(fmt, "\n {:1$}", "", hex_width)); + } + + if let Some(name) = symbol.name() { + try!(write!(fmt, " - {}", name)); + } else { + try!(write!(fmt, " - ")); + } + + if let (Some(file), Some(line)) = (symbol.filename(), symbol.lineno()) { + try!(write!(fmt, "\n {:3$}at {}:{}", "", file.display(), line, hex_width)); + } + } + } + + Ok(()) + } +} + +impl Default for Backtrace { + fn default() -> Backtrace { + Backtrace::new() + } +} diff --git a/backtrace-0.3.5/src/dylib.rs b/backtrace-0.3.5/src/dylib.rs new file mode 100644 index 000000000..34fb0bf16 --- /dev/null +++ b/backtrace-0.3.5/src/dylib.rs @@ -0,0 +1,70 @@ +use std::ffi::CString; +use std::marker; +use std::mem; +use std::sync::atomic::{AtomicUsize, Ordering}; + +use libc::{self, c_char, c_void}; + +pub struct Dylib { + pub init: AtomicUsize, +} + +pub struct Symbol { + pub name: &'static str, + pub addr: AtomicUsize, + pub _marker: marker::PhantomData, +} + +impl Dylib { + pub unsafe fn get<'a, T>(&self, sym: &'a Symbol) -> Option<&'a T> { + self.load().and_then(|handle| { + sym.get(handle) + }) + } + + pub unsafe fn init(&self, path: &str) -> bool { + if self.init.load(Ordering::SeqCst) != 0 { + return true + } + let name = CString::new(path).unwrap(); + let ptr = libc::dlopen(name.as_ptr() as *const c_char, libc::RTLD_LAZY); + if ptr.is_null() { + return false + } + match self.init.compare_and_swap(0, ptr as usize, Ordering::SeqCst) { + 0 => {} + _ => { libc::dlclose(ptr); } + } + return true + } + + unsafe fn load(&self) -> Option<*mut c_void> { + match self.init.load(Ordering::SeqCst) { + 0 => None, + n => Some(n as *mut c_void), + } + } +} + +impl Symbol { + unsafe fn get(&self, handle: *mut c_void) -> Option<&T> { + assert_eq!(mem::size_of::(), mem::size_of_val(&self.addr)); + if self.addr.load(Ordering::SeqCst) == 0 { + self.addr.store(fetch(handle, self.name.as_ptr()), Ordering::SeqCst) + } + if self.addr.load(Ordering::SeqCst) == 1 { + None + } else { + mem::transmute::<&AtomicUsize, Option<&T>>(&self.addr) + } + } +} + +unsafe fn fetch(handle: *mut c_void, name: *const u8) -> usize { + let ptr = libc::dlsym(handle, name as *const _); + if ptr.is_null() { + 1 + } else { + ptr as usize + } +} diff --git a/backtrace-0.3.5/src/lib.rs b/backtrace-0.3.5/src/lib.rs new file mode 100644 index 000000000..d10637a4d --- /dev/null +++ b/backtrace-0.3.5/src/lib.rs @@ -0,0 +1,177 @@ +//! A library for acquiring a backtrace at runtime +//! +//! This library is meant to supplement the `RUST_BACKTRACE=1` support of the +//! standard library by allowing an acquisition of a backtrace at runtime +//! programmatically. The backtraces generated by this library do not need to be +//! parsed, for example, and expose the functionality of multiple backend +//! implementations. +//! +//! # Implementation +//! +//! This library makes use of a number of strategies for actually acquiring a +//! backtrace. For example unix uses libgcc's libunwind bindings by default to +//! acquire a backtrace, but coresymbolication or dladdr is used on OSX to +//! acquire symbol names while linux uses gcc's libbacktrace. +//! +//! When using the default feature set of this library the "most reasonable" set +//! of defaults is chosen for the current platform, but the features activated +//! can also be controlled at a finer granularity. +//! +//! # Platform Support +//! +//! Currently this library is verified to work on Linux, OSX, and Windows, but +//! it may work on other platforms as well. Note that the quality of the +//! backtrace may vary across platforms. +//! +//! # API Principles +//! +//! This library attempts to be as flexible as possible to accommodate different +//! backend implementations of acquiring a backtrace. Consequently the currently +//! exported functions are closure-based as opposed to the likely expected +//! iterator-based versions. This is done due to limitations of the underlying +//! APIs used from the system. +//! +//! # Usage +//! +//! First, add this to your Cargo.toml +//! +//! ```toml +//! [dependencies] +//! backtrace = "0.2" +//! ``` +//! +//! Next: +//! +//! ``` +//! extern crate backtrace; +//! +//! fn main() { +//! backtrace::trace(|frame| { +//! let ip = frame.ip(); +//! let symbol_address = frame.symbol_address(); +//! +//! // Resolve this instruction pointer to a symbol name +//! backtrace::resolve(ip, |symbol| { +//! if let Some(name) = symbol.name() { +//! // ... +//! } +//! if let Some(filename) = symbol.filename() { +//! // ... +//! } +//! }); +//! +//! true // keep going to the next frame +//! }); +//! } +//! ``` + +#![doc(html_root_url = "http://alexcrichton.com/backtrace-rs")] +#![deny(missing_docs)] +#![deny(warnings)] + +#[cfg(unix)] +extern crate libc; +#[cfg(all(windows, feature = "winapi"))] extern crate winapi; + +#[cfg(feature = "serde_derive")] +#[cfg_attr(feature = "serde_derive", macro_use)] +extern crate serde_derive; + +#[cfg(feature = "rustc-serialize")] +extern crate rustc_serialize; + +#[macro_use] +extern crate cfg_if; + +extern crate rustc_demangle; + +#[cfg(feature = "cpp_demangle")] +extern crate cpp_demangle; + +#[cfg(all(feature = "gimli-symbolize", + unix, + target_os = "linux"))] +extern crate addr2line; +#[cfg(all(feature = "gimli-symbolize", + unix, + target_os = "linux"))] +extern crate findshlibs; + +#[allow(dead_code)] // not used everywhere +#[cfg(unix)] +#[macro_use] +mod dylib; + +pub use backtrace::{trace, Frame}; +mod backtrace; + +pub use symbolize::{resolve, Symbol, SymbolName}; +mod symbolize; + +pub use capture::{Backtrace, BacktraceFrame, BacktraceSymbol}; +mod capture; + +#[allow(dead_code)] +struct Bomb { + enabled: bool, +} + +#[allow(dead_code)] +impl Drop for Bomb { + fn drop(&mut self) { + if self.enabled { + panic!("cannot panic during the backtrace function"); + } + } +} + +#[allow(dead_code)] +mod lock { + use std::cell::Cell; + use std::mem; + use std::sync::{Once, Mutex, MutexGuard, ONCE_INIT}; + + pub struct LockGuard(MutexGuard<'static, ()>); + + static mut LOCK: *mut Mutex<()> = 0 as *mut _; + static INIT: Once = ONCE_INIT; + thread_local!(static LOCK_HELD: Cell = Cell::new(false)); + + impl Drop for LockGuard { + fn drop(&mut self) { + LOCK_HELD.with(|slot| { + assert!(slot.get()); + slot.set(false); + }); + } + } + + pub fn lock() -> Option { + if LOCK_HELD.with(|l| l.get()) { + return None + } + LOCK_HELD.with(|s| s.set(true)); + unsafe { + INIT.call_once(|| { + LOCK = mem::transmute(Box::new(Mutex::new(()))); + }); + Some(LockGuard((*LOCK).lock().unwrap())) + } + } +} + +// requires external synchronization +#[cfg(all(windows, feature = "dbghelp"))] +unsafe fn dbghelp_init() { + use winapi::shared::minwindef; + use winapi::um::{dbghelp, processthreadsapi}; + + static mut INITIALIZED: bool = false; + + if !INITIALIZED { + dbghelp::SymInitializeW(processthreadsapi::GetCurrentProcess(), + 0 as *mut _, + minwindef::TRUE); + INITIALIZED = true; + } +} diff --git a/backtrace-0.3.5/src/symbolize/coresymbolication.rs b/backtrace-0.3.5/src/symbolize/coresymbolication.rs new file mode 100644 index 000000000..d26835d7f --- /dev/null +++ b/backtrace-0.3.5/src/symbolize/coresymbolication.rs @@ -0,0 +1,192 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] + +use std::ffi::{CStr, OsStr}; +use std::mem; +use std::os::raw::{c_void, c_char, c_int}; +use std::os::unix::prelude::*; +use std::path::Path; +use std::ptr; +use std::sync::atomic::ATOMIC_USIZE_INIT; + +use libc::{self, Dl_info}; + +use SymbolName; +use dylib::Dylib; +use dylib::Symbol as DylibSymbol; + +#[repr(C)] +#[derive(Copy, Clone, PartialEq)] +pub struct CSTypeRef { + cpp_data: *const c_void, + cpp_obj: *const c_void +} + +const CS_NOW: u64 = 0x80000000; +const CSREF_NULL: CSTypeRef = CSTypeRef { + cpp_data: 0 as *const c_void, + cpp_obj: 0 as *const c_void, +}; + +pub enum Symbol { + Core { + path: *const c_char, + lineno: u32, + name: *const c_char, + addr: *mut c_void, + }, + Dladdr(Dl_info), +} + +impl Symbol { + pub fn name(&self) -> Option { + let name = match *self { + Symbol::Core { name, .. } => name, + Symbol::Dladdr(ref info) => info.dli_sname, + }; + if name.is_null() { + None + } else { + Some(SymbolName::new(unsafe { + CStr::from_ptr(name).to_bytes() + })) + } + } + + pub fn addr(&self) -> Option<*mut c_void> { + match *self { + Symbol::Core { addr, .. } => Some(addr), + Symbol::Dladdr(ref info) => Some(info.dli_saddr as *mut _), + } + } + + pub fn filename(&self) -> Option<&Path> { + match *self { + Symbol::Core { path, .. } => { + if path.is_null() { + None + } else { + Some(Path::new(OsStr::from_bytes(unsafe { + CStr::from_ptr(path).to_bytes() + }))) + } + } + Symbol::Dladdr(_) => None, + } + } + + pub fn lineno(&self) -> Option { + match *self { + Symbol::Core { lineno: 0, .. } => None, + Symbol::Core { lineno, .. } => Some(lineno), + Symbol::Dladdr(_) => None, + } + } +} + +static CORESYMBOLICATION: Dylib = Dylib { init: ATOMIC_USIZE_INIT }; + +macro_rules! dlsym { + (extern { + $(fn $name:ident($($arg:ident: $t:ty),*) -> $ret:ty;)* + }) => ($( + static $name: ::dylib::Symbol $ret> = + ::dylib::Symbol { + name: concat!(stringify!($name), "\0"), + addr: ::std::sync::atomic::ATOMIC_USIZE_INIT, + _marker: ::std::marker::PhantomData, + }; + )*) +} + +dlsym! { + extern { + fn CSSymbolicatorCreateWithPid(pid: c_int) -> CSTypeRef; + fn CSRelease(rf: CSTypeRef) -> c_void; + fn CSSymbolicatorGetSymbolWithAddressAtTime( + cs: CSTypeRef, addr: *const c_void, time: u64) -> CSTypeRef; + fn CSSymbolicatorGetSourceInfoWithAddressAtTime( + cs: CSTypeRef, addr: *const c_void, time: u64) -> CSTypeRef; + fn CSSourceInfoGetLineNumber(info: CSTypeRef) -> c_int; + fn CSSourceInfoGetPath(info: CSTypeRef) -> *const c_char; + fn CSSourceInfoGetSymbol(info: CSTypeRef) -> CSTypeRef; + fn CSSymbolGetName(sym: CSTypeRef) -> *const c_char; + fn CSSymbolGetSymbolOwner(sym: CSTypeRef) -> CSTypeRef; + fn CSSymbolOwnerGetBaseAddress(symowner: CSTypeRef) -> *mut c_void; + } +} + +unsafe fn get(sym: &DylibSymbol) -> &T { + CORESYMBOLICATION.get(sym).unwrap() +} + +unsafe fn try_resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) -> bool { + let path = "/System/Library/PrivateFrameworks/CoreSymbolication.framework\ + /Versions/A/CoreSymbolication"; + if !CORESYMBOLICATION.init(path) { + return false; + } + + let cs = get(&CSSymbolicatorCreateWithPid)(libc::getpid()); + if cs == CSREF_NULL { + return false + } + + let info = get(&CSSymbolicatorGetSourceInfoWithAddressAtTime)( + cs, addr, CS_NOW); + let sym = if info == CSREF_NULL { + get(&CSSymbolicatorGetSymbolWithAddressAtTime)(cs, addr, CS_NOW) + } else { + get(&CSSourceInfoGetSymbol)(info) + }; + + let mut rv = false; + if sym != CSREF_NULL { + let owner = get(&CSSymbolGetSymbolOwner)(sym); + if owner != CSREF_NULL { + cb(&super::Symbol { + inner: Symbol::Core { + path: if info != CSREF_NULL { + get(&CSSourceInfoGetPath)(info) + } else { + ptr::null() + }, + lineno: if info != CSREF_NULL { + get(&CSSourceInfoGetLineNumber)(info) as u32 + } else { + 0 + }, + name: get(&CSSymbolGetName)(sym), + addr: get(&CSSymbolOwnerGetBaseAddress)(owner), + }, + }); + rv = true; + } + } + get(&CSRelease)(cs); + + rv +} + +pub fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) { + unsafe { + if try_resolve(addr, cb) { + return + } + let mut info: Dl_info = mem::zeroed(); + if libc::dladdr(addr as *mut _, &mut info) != 0 { + cb(&super::Symbol { + inner: Symbol::Dladdr(info), + }); + } + } +} diff --git a/backtrace-0.3.5/src/symbolize/dbghelp.rs b/backtrace-0.3.5/src/symbolize/dbghelp.rs new file mode 100644 index 000000000..a2c990612 --- /dev/null +++ b/backtrace-0.3.5/src/symbolize/dbghelp.rs @@ -0,0 +1,118 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] + +use std::ffi::OsString; +use std::mem; +use std::path::Path; +use std::os::windows::prelude::*; +use std::slice; +use winapi::ctypes::*; +use winapi::shared::basetsd::*; +use winapi::shared::minwindef::*; +use winapi::um::processthreadsapi; +use winapi::um::dbghelp; +use winapi::um::dbghelp::*; + +use SymbolName; + +pub struct Symbol { + name: OsString, + addr: *mut c_void, + line: Option, + filename: Option, +} + +impl Symbol { + pub fn name(&self) -> Option { + self.name.to_str().map(|s| SymbolName::new(s.as_bytes())) + } + + pub fn addr(&self) -> Option<*mut c_void> { + Some(self.addr as *mut _) + } + + pub fn filename(&self) -> Option<&Path> { + self.filename.as_ref().map(Path::new) + } + + pub fn lineno(&self) -> Option { + self.line + } +} + +pub fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) { + // According to windows documentation, all dbghelp functions are + // single-threaded. + let _g = ::lock::lock(); + + unsafe { + let size = 2 * MAX_SYM_NAME + mem::size_of::(); + let mut data = vec![0u8; size]; + let info = &mut *(data.as_mut_ptr() as *mut SYMBOL_INFOW); + info.MaxNameLen = MAX_SYM_NAME as ULONG; + // the struct size in C. the value is different to + // `size_of::() - MAX_SYM_NAME + 1` (== 81) + // due to struct alignment. + info.SizeOfStruct = 88; + + let _c = ::dbghelp_init(); + + let mut displacement = 0u64; + let ret = dbghelp::SymFromAddrW(processthreadsapi::GetCurrentProcess(), + addr as DWORD64, + &mut displacement, + info); + if ret != TRUE { + return + } + + // If the symbol name is greater than MaxNameLen, SymFromAddrW will + // give a buffer of (MaxNameLen - 1) characters and set NameLen to + // the real value. + let name_len = ::std::cmp::min(info.NameLen as usize, + info.MaxNameLen as usize - 1); + + let name = slice::from_raw_parts(info.Name.as_ptr() as *const u16, + name_len); + let name = OsString::from_wide(name); + + let mut line = mem::zeroed::(); + line.SizeOfStruct = mem::size_of::() as DWORD; + let mut displacement = 0; + let ret = dbghelp::SymGetLineFromAddrW64(processthreadsapi::GetCurrentProcess(), + addr as DWORD64, + &mut displacement, + &mut line); + let mut filename = None; + let mut lineno = None; + if ret == TRUE { + lineno = Some(line.LineNumber as u32); + + let base = line.FileName; + let mut len = 0; + while *base.offset(len) != 0 { + len += 1; + } + let name = slice::from_raw_parts(base, len as usize); + filename = Some(OsString::from_wide(name)); + } + + cb(&super::Symbol { + inner: Symbol { + name: name, + addr: info.Address as *mut _, + line: lineno, + filename: filename, + }, + }) + } +} diff --git a/backtrace-0.3.5/src/symbolize/dladdr.rs b/backtrace-0.3.5/src/symbolize/dladdr.rs new file mode 100644 index 000000000..d7cdfbb8b --- /dev/null +++ b/backtrace-0.3.5/src/symbolize/dladdr.rs @@ -0,0 +1,59 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ffi::CStr; +use std::mem; +use std::os::raw::c_void; +use std::path::Path; + +use libc::{self, Dl_info}; + +use SymbolName; + +pub struct Symbol { + inner: Dl_info, +} + +impl Symbol { + pub fn name(&self) -> Option { + if self.inner.dli_sname.is_null() { + None + } else { + Some(SymbolName::new(unsafe { + CStr::from_ptr(self.inner.dli_sname).to_bytes() + })) + } + } + + pub fn addr(&self) -> Option<*mut c_void> { + Some(self.inner.dli_saddr as *mut _) + } + + pub fn filename(&self) -> Option<&Path> { + None + } + + pub fn lineno(&self) -> Option { + None + } +} + +pub fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) { + unsafe { + let mut info: super::Symbol = super::Symbol { + inner: Symbol { + inner: mem::zeroed(), + }, + }; + if libc::dladdr(addr as *mut _, &mut info.inner.inner) != 0 { + cb(&info) + } + } +} diff --git a/backtrace-0.3.5/src/symbolize/gimli.rs b/backtrace-0.3.5/src/symbolize/gimli.rs new file mode 100644 index 000000000..5ee715053 --- /dev/null +++ b/backtrace-0.3.5/src/symbolize/gimli.rs @@ -0,0 +1,170 @@ +use addr2line; +use findshlibs::{self, Segment, SharedLibrary}; +use std::cell::RefCell; +use std::env; +use std::os::raw::c_void; +use std::path::{Path, PathBuf}; +use std::u32; + +use SymbolName; + +const MAPPINGS_CACHE_SIZE: usize = 4; + +thread_local! { + // A very small, very simple LRU cache for debug info mappings. + // + // The hit rate should be very high, since the typical stack doesn't cross + // between many shared libraries. + // + // The `addr2line::Mapping` structures are pretty expensive to create. Its + // cost is expected to be amortized by subsequent `locate` queries, which + // leverage the structures built when constructing `addr2line::Mapping`s to + // get nice speedups. If we didn't have this cache, that amortization would + // never happen, and symbolicating backtraces would be ssssllllooooowwww. + static MAPPINGS_CACHE: RefCell> + = RefCell::new(Vec::with_capacity(MAPPINGS_CACHE_SIZE)); +} + +fn with_mapping_for_path(path: PathBuf, mut f: F) +where + F: FnMut(&mut addr2line::Mapping) +{ + MAPPINGS_CACHE.with(|cache| { + let mut cache = cache.borrow_mut(); + + let idx = cache.iter().position(|&(ref p, _)| p == &path); + + // Invariant: after this conditional completes without early returning + // from an error, the cache entry for this path is at index 0. + + if let Some(idx) = idx { + // When the mapping is already in the cache, move it to the front. + if idx != 0 { + let entry = cache.remove(idx); + cache.insert(0, entry); + } + } else { + // When the mapping is not in the cache, create a new mapping, + // insert it into the front of the cache, and evict the oldest cache + // entry if necessary. + let opts = addr2line::Options::default() + .with_functions(); + + let mapping = match opts.build(&path) { + Err(_) => return, + Ok(m) => m, + }; + + if cache.len() == MAPPINGS_CACHE_SIZE { + cache.pop(); + } + + cache.insert(0, (path, mapping)); + } + + f(&mut cache[0].1); + }); +} + +pub fn resolve(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) { + // First, find the file containing the segment that the given AVMA (after + // relocation) address falls within. Use the containing segment to compute + // the SVMA (before relocation) address. + // + // Note that the OS APIs that `SharedLibrary::each` is implemented with hold + // a lock for the duration of the `each` call, so we want to keep this + // section as short as possible to avoid contention with other threads + // capturing backtraces. + let addr = findshlibs::Avma(addr as *mut u8 as *const u8); + let mut so_info = None; + findshlibs::TargetSharedLibrary::each(|so| { + use findshlibs::IterationControl::*; + + for segment in so.segments() { + if segment.contains_avma(so, addr) { + let addr = so.avma_to_svma(addr); + let path = so.name().to_string_lossy(); + so_info = Some((addr, path.to_string())); + return Break; + } + } + + Continue + }); + let (addr, path) = match so_info { + None => return, + Some((a, p)) => (a, p), + }; + + // Second, fixup the path. Empty path means that this address falls within + // the main executable, not a shared library. + let path = if path.is_empty() { + match env::current_exe() { + Err(_) => return, + Ok(p) => p, + } + } else { + PathBuf::from(path) + }; + + // Finally, get a cached mapping or create a new mapping for this file, and + // evaluate the DWARF info to find the file/line/name for this address. + with_mapping_for_path(path, |mapping| { + let (file, line, func) = match mapping.locate(addr.0 as u64) { + Ok(None) | Err(_) => return, + Ok(Some((file, line, func))) => (file, line, func), + }; + + let sym = super::Symbol { + inner: Symbol::new(addr.0 as usize, + file, + line, + func.map(|f| f.to_string())) + }; + + cb(&sym); + }); +} + +pub struct Symbol { + addr: usize, + file: PathBuf, + line: Option, + name: Option, +} + +impl Symbol { + fn new(addr: usize, + file: PathBuf, + line: Option, + name: Option) + -> Symbol { + Symbol { + addr, + file, + line, + name, + } + } + + pub fn name(&self) -> Option { + self.name.as_ref().map(|s| SymbolName::new(s.as_bytes())) + } + + pub fn addr(&self) -> Option<*mut c_void> { + Some(self.addr as *mut c_void) + } + + pub fn filename(&self) -> Option<&Path> { + Some(self.file.as_ref()) + } + + pub fn lineno(&self) -> Option { + self.line + .and_then(|l| if l > (u32::MAX as u64) { + None + } else { + Some(l as u32) + }) + } +} diff --git a/backtrace-0.3.5/src/symbolize/libbacktrace.rs b/backtrace-0.3.5/src/symbolize/libbacktrace.rs new file mode 100644 index 000000000..865f69181 --- /dev/null +++ b/backtrace-0.3.5/src/symbolize/libbacktrace.rs @@ -0,0 +1,180 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] + +extern crate backtrace_sys as bt; + +use libc::uintptr_t; +use std::ffi::{CStr, OsStr}; +use std::os::raw::{c_void, c_char, c_int}; +use std::os::unix::prelude::*; +use std::path::Path; +use std::ptr; +use std::sync::{ONCE_INIT, Once}; + +use SymbolName; + +pub enum Symbol { + Syminfo { + pc: uintptr_t, + symname: *const c_char, + }, + Pcinfo { + pc: uintptr_t, + filename: *const c_char, + lineno: c_int, + function: *const c_char, + }, +} + +impl Symbol { + pub fn name(&self) -> Option { + let ptr = match *self { + Symbol::Syminfo { symname, .. } => symname, + Symbol::Pcinfo { function, .. } => function, + }; + if ptr.is_null() { + None + } else { + Some(SymbolName::new(unsafe { CStr::from_ptr(ptr).to_bytes() })) + } + } + + pub fn addr(&self) -> Option<*mut c_void> { + let pc = match *self { + Symbol::Syminfo { pc, .. } => pc, + Symbol::Pcinfo { pc, .. } => pc, + }; + if pc == 0 {None} else {Some(pc as *mut _)} + } + + pub fn filename(&self) -> Option<&Path> { + match *self { + Symbol::Syminfo { .. } => None, + Symbol::Pcinfo { filename, .. } => { + Some(Path::new(OsStr::from_bytes(unsafe { + CStr::from_ptr(filename).to_bytes() + }))) + } + } + } + + pub fn lineno(&self) -> Option { + match *self { + Symbol::Syminfo { .. } => None, + Symbol::Pcinfo { lineno, .. } => Some(lineno as u32), + } + } +} + +extern fn error_cb(_data: *mut c_void, _msg: *const c_char, + _errnum: c_int) { + // do nothing for now +} + +extern fn syminfo_cb(data: *mut c_void, + pc: uintptr_t, + symname: *const c_char, + _symval: uintptr_t, + _symsize: uintptr_t) { + unsafe { + call(data, &super::Symbol { + inner: Symbol::Syminfo { + pc: pc, + symname: symname, + }, + }); + } +} + +extern fn pcinfo_cb(data: *mut c_void, + pc: uintptr_t, + filename: *const c_char, + lineno: c_int, + function: *const c_char) -> c_int { + unsafe { + if filename.is_null() || function.is_null() { + return -1 + } + call(data, &super::Symbol { + inner: Symbol::Pcinfo { + pc: pc, + filename: filename, + lineno: lineno, + function: function, + }, + }); + return 0 + } +} + +unsafe fn call(data: *mut c_void, sym: &super::Symbol) { + let cb = data as *mut &mut FnMut(&super::Symbol); + let mut bomb = ::Bomb { enabled: true }; + (*cb)(sym); + bomb.enabled = false; +} + +// The libbacktrace API supports creating a state, but it does not +// support destroying a state. I personally take this to mean that a +// state is meant to be created and then live forever. +// +// I would love to register an at_exit() handler which cleans up this +// state, but libbacktrace provides no way to do so. +// +// With these constraints, this function has a statically cached state +// that is calculated the first time this is requested. Remember that +// backtracing all happens serially (one global lock). +// +// Things don't work so well on not-Linux since libbacktrace can't track down +// that executable this is. We at one point used env::current_exe but it turns +// out that there are some serious security issues with that approach. +// +// Specifically, on certain platforms like BSDs, a malicious actor can cause an +// arbitrary file to be placed at the path returned by current_exe. libbacktrace +// does not behave defensively in the presence of ill-formed DWARF information, +// and has been demonstrated to segfault in at least one case. There is no +// evidence at the moment to suggest that a more carefully constructed file +// can't cause arbitrary code execution. As a result of all of this, we don't +// hint libbacktrace with the path to the current process. +unsafe fn init_state() -> *mut bt::backtrace_state { + static mut STATE: *mut bt::backtrace_state = 0 as *mut _; + static INIT: Once = ONCE_INIT; + INIT.call_once(|| { + // Our libbacktrace may not have multithreading support, so + // set `threaded = 0` and synchronize ourselves. + STATE = bt::backtrace_create_state(ptr::null(), 0, error_cb, + ptr::null_mut()); + }); + + STATE +} + +pub fn resolve(symaddr: *mut c_void, mut cb: &mut FnMut(&super::Symbol)) { + let _guard = ::lock::lock(); + + // backtrace errors are currently swept under the rug + unsafe { + let state = init_state(); + if state.is_null() { + return + } + + let ret = bt::backtrace_pcinfo(state, symaddr as uintptr_t, + pcinfo_cb, error_cb, + &mut cb as *mut _ as *mut _); + if ret != 0 { + bt::backtrace_syminfo(state, symaddr as uintptr_t, + syminfo_cb, error_cb, + &mut cb as *mut _ as *mut _); + } + } +} diff --git a/backtrace-0.3.5/src/symbolize/mod.rs b/backtrace-0.3.5/src/symbolize/mod.rs new file mode 100644 index 000000000..f3d542c67 --- /dev/null +++ b/backtrace-0.3.5/src/symbolize/mod.rs @@ -0,0 +1,290 @@ +use std::fmt; +#[cfg(not(feature = "cpp_demangle"))] +use std::marker::PhantomData; +use std::os::raw::c_void; +use std::path::Path; +use std::str; +use rustc_demangle::{try_demangle, Demangle}; + +/// Resolve an address to a symbol, passing the symbol to the specified +/// closure. +/// +/// This function will look up the given address in areas such as the local +/// symbol table, dynamic symbol table, or DWARF debug info (depending on the +/// activated implementation) to find symbols to yield. +/// +/// The closure may not be called if resolution could not be performed, and it +/// also may be called more than once in the case of inlined functions. +/// +/// Symbols yielded represent the execution at the specified `addr`, returning +/// file/line pairs for that address (if available). +/// +/// # Example +/// +/// ``` +/// extern crate backtrace; +/// +/// fn main() { +/// backtrace::trace(|frame| { +/// let ip = frame.ip(); +/// +/// backtrace::resolve(ip, |symbol| { +/// // ... +/// }); +/// +/// false // only look at the top frame +/// }); +/// } +/// ``` +pub fn resolve(addr: *mut c_void, mut cb: F) { + resolve_imp(addr, &mut cb) +} + +/// A trait representing the resolution of a symbol in a file. +/// +/// This trait is yielded as a trait object to the closure given to the +/// `backtrace::resolve` function, and it is virtually dispatched as it's +/// unknown which implementation is behind it. +/// +/// A symbol can give contextual information about a function, for example the +/// name, filename, line number, precise address, etc. Not all information is +/// always available in a symbol, however, so all methods return an `Option`. +pub struct Symbol { + inner: SymbolImp, +} + +impl Symbol { + /// Returns the name of this function. + /// + /// The returned structure can be used to query various properties about the + /// symbol name: + /// + /// * The `Display` implementation will print out the demangled symbol. + /// * The raw `str` value of the symbol can be accessed (if it's valid + /// utf-8). + /// * The raw bytes for the symbol name can be accessed. + pub fn name(&self) -> Option { + self.inner.name() + } + + /// Returns the starting address of this function. + pub fn addr(&self) -> Option<*mut c_void> { + self.inner.addr() + } + + /// Returns the file name where this function was defined. + /// + /// This is currently only available when libbacktrace is being used (e.g. + /// unix platforms other than OSX) and when a binary is compiled with + /// debuginfo. If neither of these conditions is met then this will likely + /// return `None`. + pub fn filename(&self) -> Option<&Path> { + self.inner.filename() + } + + /// Returns the line number for where this symbol is currently executing. + /// + /// This return value is typically `Some` if `filename` returns `Some`, and + /// is consequently subject to similar caveats. + pub fn lineno(&self) -> Option { + self.inner.lineno() + } +} + +impl fmt::Debug for Symbol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut d = f.debug_struct("Symbol"); + if let Some(name) = self.name() { + d.field("name", &name); + } + if let Some(addr) = self.addr() { + d.field("addr", &addr); + } + if let Some(filename) = self.filename() { + d.field("filename", &filename); + } + if let Some(lineno) = self.lineno() { + d.field("lineno", &lineno); + } + d.finish() + } +} + + +cfg_if! { + if #[cfg(feature = "cpp_demangle")] { + // Maybe a parsed C++ symbol, if parsing the mangled symbol as Rust + // failed. + struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>); + + impl<'a> OptionCppSymbol<'a> { + fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> { + OptionCppSymbol(::cpp_demangle::BorrowedSymbol::new(input).ok()) + } + + fn none() -> OptionCppSymbol<'a> { + OptionCppSymbol(None) + } + } + } else { + // Make sure to keep this zero-sized, so that the `cpp_demangle` feature + // has no cost when disabled. + struct OptionCppSymbol<'a>(PhantomData<&'a ()>); + + impl<'a> OptionCppSymbol<'a> { + fn parse(_: &'a [u8]) -> OptionCppSymbol<'a> { + OptionCppSymbol(PhantomData) + } + + fn none() -> OptionCppSymbol<'a> { + OptionCppSymbol(PhantomData) + } + } + } +} + +/// A wrapper around a symbol name to provide ergonomic accessors to the +/// demangled name, the raw bytes, the raw string, etc. +// Allow dead code for when the `cpp_demangle` feature is not enabled. +#[allow(dead_code)] +pub struct SymbolName<'a> { + bytes: &'a [u8], + demangled: Option>, + cpp_demangled: OptionCppSymbol<'a>, +} + +impl<'a> SymbolName<'a> { + /// Creates a new symbol name from the raw underlying bytes. + pub fn new(bytes: &'a [u8]) -> SymbolName<'a> { + let str_bytes = str::from_utf8(bytes).ok(); + let demangled = str_bytes.and_then(|s| try_demangle(s).ok()); + + let cpp = if demangled.is_none() { + OptionCppSymbol::parse(bytes) + } else { + OptionCppSymbol::none() + }; + + SymbolName { + bytes: bytes, + demangled: demangled, + cpp_demangled: cpp, + } + } + + /// Returns the raw symbol name as a `str` if the symbols is valid utf-8. + pub fn as_str(&self) -> Option<&'a str> { + self.demangled + .as_ref() + .map(|s| s.as_str()) + .or_else(|| { + str::from_utf8(self.bytes).ok() + }) + } + + /// Returns the raw symbol name as a list of bytes + pub fn as_bytes(&self) -> &'a [u8] { + self.bytes + } +} + +cfg_if! { + if #[cfg(feature = "cpp_demangle")] { + impl<'a> fmt::Display for SymbolName<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(ref s) = self.demangled { + s.fmt(f) + } else if let Some(ref cpp) = self.cpp_demangled.0 { + cpp.fmt(f) + } else { + String::from_utf8_lossy(self.bytes).fmt(f) + } + } + } + } else { + impl<'a> fmt::Display for SymbolName<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(ref s) = self.demangled { + s.fmt(f) + } else { + String::from_utf8_lossy(self.bytes).fmt(f) + } + } + } + } +} + +cfg_if! { + if #[cfg(feature = "cpp_demangle")] { + impl<'a> fmt::Debug for SymbolName<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use std::fmt::Write; + + if let Some(ref s) = self.demangled { + return s.fmt(f) + } + + // This may to print if the demangled symbol isn't actually + // valid, so handle the error here gracefully by not propagating + // it outwards. + if let Some(ref cpp) = self.cpp_demangled.0 { + let mut s = String::new(); + if write!(s, "{}", cpp).is_ok() { + return s.fmt(f) + } + } + + String::from_utf8_lossy(self.bytes).fmt(f) + } + } + } else { + impl<'a> fmt::Debug for SymbolName<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(ref s) = self.demangled { + s.fmt(f) + } else { + String::from_utf8_lossy(self.bytes).fmt(f) + } + } + } + } +} + +cfg_if! { + if #[cfg(all(windows, feature = "dbghelp"))] { + mod dbghelp; + use self::dbghelp::resolve as resolve_imp; + use self::dbghelp::Symbol as SymbolImp; + } else if #[cfg(all(feature = "gimli-symbolize", + unix, + target_os = "linux"))] { + mod gimli; + use self::gimli::resolve as resolve_imp; + use self::gimli::Symbol as SymbolImp; + } else if #[cfg(all(feature = "libbacktrace", + unix, + not(target_os = "fuchsia"), + not(target_os = "emscripten"), + not(target_os = "macos"), + not(target_os = "ios")))] { + mod libbacktrace; + use self::libbacktrace::resolve as resolve_imp; + use self::libbacktrace::Symbol as SymbolImp; + } else if #[cfg(all(feature = "coresymbolication", + any(target_os = "macos", + target_os = "ios")))] { + mod coresymbolication; + use self::coresymbolication::resolve as resolve_imp; + use self::coresymbolication::Symbol as SymbolImp; + } else if #[cfg(all(unix, + not(target_os = "emscripten"), + feature = "dladdr"))] { + mod dladdr; + use self::dladdr::resolve as resolve_imp; + use self::dladdr::Symbol as SymbolImp; + } else { + mod noop; + use self::noop::resolve as resolve_imp; + use self::noop::Symbol as SymbolImp; + } +} diff --git a/backtrace-0.3.5/src/symbolize/noop.rs b/backtrace-0.3.5/src/symbolize/noop.rs new file mode 100644 index 000000000..78b2a63f8 --- /dev/null +++ b/backtrace-0.3.5/src/symbolize/noop.rs @@ -0,0 +1,27 @@ +use std::path::Path; +use std::os::raw::c_void; + +use SymbolName; + +pub fn resolve(_addr: *mut c_void, _cb: &mut FnMut(&super::Symbol)) { +} + +pub struct Symbol; + +impl Symbol { + pub fn name(&self) -> Option { + None + } + + pub fn addr(&self) -> Option<*mut c_void> { + None + } + + pub fn filename(&self) -> Option<&Path> { + None + } + + pub fn lineno(&self) -> Option { + None + } +} diff --git a/backtrace-0.3.5/tests/long_fn_name.rs b/backtrace-0.3.5/tests/long_fn_name.rs new file mode 100644 index 000000000..ce93671a6 --- /dev/null +++ b/backtrace-0.3.5/tests/long_fn_name.rs @@ -0,0 +1,57 @@ +extern crate backtrace; + +#[cfg(all(windows, feature = "dbghelp"))] +extern crate winapi; + +use backtrace::Backtrace; + +// 50-character module name +mod _234567890_234567890_234567890_234567890_234567890 { + // 50-character struct name + #[allow(non_camel_case_types)] + pub struct _234567890_234567890_234567890_234567890_234567890(T); + impl _234567890_234567890_234567890_234567890_234567890 { + #[allow(dead_code)] + pub fn new() -> ::Backtrace { + ::Backtrace::new() + } + } +} + +// Long function names must be truncated to (MAX_SYM_NAME - 1) characters. +// Only run this test for msvc, since gnu prints "" for all frames. +#[test] +#[cfg(all(windows, feature = "dbghelp", target_env = "msvc"))] +fn test_long_fn_name() { + use winapi::um::dbghelp; + use _234567890_234567890_234567890_234567890_234567890:: + _234567890_234567890_234567890_234567890_234567890 as S; + + // 10 repetitions of struct name, so fully qualified function name is + // atleast 10 * (50 + 50) * 2 = 2000 characters long. + // It's actually longer since it also includes `::`, `<>` and the + // name of the current module + let bt = S::>>>>>>>>>::new(); + println!("{:?}", bt); + + let mut found_long_name_frame = false; + + for frame in bt.frames() { + let symbols = frame.symbols(); + if symbols.is_empty() { + continue; + } + + if let Some(function_name) = symbols[0].name() { + let function_name = function_name.as_str().unwrap(); + if function_name.contains( + "::_234567890_234567890_234567890_234567890_234567890") + { + found_long_name_frame = true; + assert_eq!(function_name.len(), dbghelp::MAX_SYM_NAME - 1); + } + } + } + + assert!(found_long_name_frame); +} diff --git a/backtrace-0.3.5/tests/smoke.rs b/backtrace-0.3.5/tests/smoke.rs new file mode 100644 index 000000000..1e4a5ce0c --- /dev/null +++ b/backtrace-0.3.5/tests/smoke.rs @@ -0,0 +1,171 @@ +extern crate backtrace; + +use std::os::raw::c_void; +use std::thread; + +static LIBUNWIND: bool = cfg!(all(unix, feature = "libunwind")); +static UNIX_BACKTRACE: bool = cfg!(all(unix, feature = "unix-backtrace")); +static LIBBACKTRACE: bool = cfg!(all(unix, feature = "libbacktrace")) && + !cfg!(target_os = "fuchsia") && !cfg!(target_os = "macos") && + !cfg!(target_os = "ios"); +static CORESYMBOLICATION: bool = cfg!(all(any(target_os = "macos", target_os = "ios"), + feature = "coresymbolication")); +static DLADDR: bool = cfg!(all(unix, feature = "dladdr")) && !cfg!(target_os = "fuchsia"); +static DBGHELP: bool = cfg!(all(windows, feature = "dbghelp")); +static MSVC: bool = cfg!(target_env = "msvc"); +static GIMLI_SYMBOLIZE: bool = cfg!(all(feature = "gimli-symbolize", + unix, + target_os = "linux")); + +#[test] +fn smoke_test_frames() { + frame_1(line!()); + #[inline(never)] fn frame_1(start_line: u32) { frame_2(start_line) } + #[inline(never)] fn frame_2(start_line: u32) { frame_3(start_line) } + #[inline(never)] fn frame_3(start_line: u32) { frame_4(start_line) } + #[inline(never)] fn frame_4(start_line: u32) { + let mut v = Vec::new(); + backtrace::trace(|cx| { + v.push((cx.ip(), cx.symbol_address())); + true + }); + + if v.len() < 5 { + assert!(!LIBUNWIND); + assert!(!UNIX_BACKTRACE); + assert!(!DBGHELP); + return + } + + // On 32-bit windows apparently the first frame isn't our backtrace + // frame but it's actually this frame. I'm not entirely sure why, but at + // least it seems consistent? + let o = if cfg!(all(windows, target_pointer_width = "32")) {1} else {0}; + // frame offset 0 is the `backtrace::trace` function, but that's generic + assert_frame(&v, o, 1, frame_4 as usize, "frame_4", + "tests/smoke.rs", start_line + 6); + assert_frame(&v, o, 2, frame_3 as usize, "frame_3", "tests/smoke.rs", + start_line + 3); + assert_frame(&v, o, 3, frame_2 as usize, "frame_2", "tests/smoke.rs", + start_line + 2); + assert_frame(&v, o, 4, frame_1 as usize, "frame_1", "tests/smoke.rs", + start_line + 1); + assert_frame(&v, o, 5, smoke_test_frames as usize, + "smoke_test_frames", "", 0); + } + + fn assert_frame(syms: &[(*mut c_void, *mut c_void)], + offset: usize, + idx: usize, + actual_fn_pointer: usize, + expected_name: &str, + expected_file: &str, + expected_line: u32) { + if offset > idx { return } + let (ip, sym) = syms[idx - offset]; + let ip = ip as usize; + let sym = sym as usize; + assert!(ip >= sym); + assert!(sym >= actual_fn_pointer); + + // windows dbghelp is *quite* liberal (and wrong) in many of its reports + // right now... + if !DBGHELP { + assert!(sym - actual_fn_pointer < 1024); + } + + let mut resolved = 0; + let can_resolve = DLADDR || LIBBACKTRACE || CORESYMBOLICATION || DBGHELP || GIMLI_SYMBOLIZE; + + let mut name = None; + let mut addr = None; + let mut line = None; + let mut file = None; + backtrace::resolve(ip as *mut c_void, |sym| { + resolved += 1; + name = sym.name().map(|v| v.to_string()); + addr = sym.addr(); + line = sym.lineno(); + file = sym.filename().map(|v| v.to_path_buf()); + }); + + // dbghelp doesn't always resolve symbols right now + match resolved { + 0 => return assert!(!can_resolve || DBGHELP), + _ => {} + } + + // * linux dladdr doesn't work (only consults local symbol table) + // * windows dbghelp isn't great for GNU + if can_resolve && + !(cfg!(target_os = "linux") && DLADDR) && + !(DBGHELP && !MSVC) + { + let name = name.expect("didn't find a name"); + assert!(name.contains(expected_name), + "didn't find `{}` in `{}`", expected_name, name); + } + + if can_resolve { + addr.expect("didn't find a symbol"); + } + + if (LIBBACKTRACE || CORESYMBOLICATION || (DBGHELP && MSVC)) && cfg!(debug_assertions) { + let line = line.expect("didn't find a line number"); + let file = file.expect("didn't find a line number"); + if !expected_file.is_empty() { + assert!(file.ends_with(expected_file), + "{:?} didn't end with {:?}", file, expected_file); + } + if expected_line != 0 { + assert!(line == expected_line, + "bad line number on frame for `{}`: {} != {}", + expected_name, line, expected_line); + } + } + } +} + +#[test] +fn many_threads() { + let threads = (0..16).map(|_| { + thread::spawn(|| { + for _ in 0..16 { + backtrace::trace(|frame| { + backtrace::resolve(frame.ip(), |symbol| { + let _s = symbol.name().map(|s| s.to_string()); + }); + true + }); + } + }) + }).collect::>(); + + for t in threads { + t.join().unwrap() + } +} + +#[test] +#[cfg(feature = "rustc-serialize")] +fn is_rustc_serialize() { + extern crate rustc_serialize; + + fn is_encode() {} + fn is_decode() {} + + is_encode::(); + is_decode::(); +} + +#[test] +#[cfg(feature = "serde")] +fn is_serde() { + extern crate serde; + + fn is_serialize() {} + fn is_deserialize() {} + + is_serialize::(); + is_deserialize::(); +} diff --git a/backtrace-sys-0.1.16/.cargo-checksum.json b/backtrace-sys-0.1.16/.cargo-checksum.json new file mode 100644 index 000000000..67e744a2a --- /dev/null +++ b/backtrace-sys-0.1.16/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"} \ No newline at end of file diff --git a/backtrace-sys-0.1.16/Cargo.toml b/backtrace-sys-0.1.16/Cargo.toml new file mode 100644 index 000000000..6f3478f52 --- /dev/null +++ b/backtrace-sys-0.1.16/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "backtrace-sys" +version = "0.1.16" +authors = ["Alex Crichton "] +build = "build.rs" +description = "Bindings to the libbacktrace gcc library\n" +homepage = "https://github.com/alexcrichton/backtrace-rs" +documentation = "http://alexcrichton.com/backtrace-rs" +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/backtrace-rs" +[dependencies.libc] +version = "0.2" +[build-dependencies.cc] +version = "1.0" diff --git a/backtrace-sys-0.1.16/build.rs b/backtrace-sys-0.1.16/build.rs new file mode 100644 index 000000000..d59973d4d --- /dev/null +++ b/backtrace-sys-0.1.16/build.rs @@ -0,0 +1,178 @@ +extern crate cc; + +use std::env; +use std::ffi::OsString; +use std::fs; +use std::io; +use std::path::PathBuf; +use std::process::Command; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +fn try_tool(compiler: &cc::Tool, cc: &str, compiler_suffix: &str, tool_suffix: &str) + -> Option { + if !cc.ends_with(compiler_suffix) { + return None + } + let cc = cc.replace(compiler_suffix, tool_suffix); + let candidate = compiler.path().parent().unwrap().join(cc); + if Command::new(&candidate).output().is_ok() { + Some(candidate) + } else { + None + } +} + +fn find_tool(compiler: &cc::Tool, cc: &str, tool: &str) -> PathBuf { + // Allow overrides via env var + if let Some(s) = env::var_os(tool.to_uppercase()) { + return s.into() + } + let tool_suffix = format!("-{}", tool); + try_tool(compiler, cc, "-gcc", &tool_suffix) + .or_else(|| try_tool(compiler, cc, "-clang", &tool_suffix)) + .or_else(|| try_tool(compiler, cc, "-cc", &tool_suffix)) + .unwrap_or_else(|| PathBuf::from(tool)) +} + +fn main() { + let src = env::current_dir().unwrap(); + let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let target = env::var("TARGET").unwrap(); + let host = env::var("HOST").unwrap(); + + // libbacktrace doesn't currently support Mach-O files + if target.contains("darwin") { + return + } + + // libbacktrace isn't used on windows + if target.contains("windows") { + return + } + + // no way this will ever compile for emscripten + if target.contains("emscripten") { + return + } + + let mut make = "make"; + + // host BSDs has GNU-make as gmake + if host.contains("bitrig") || host.contains("dragonfly") || + host.contains("freebsd") || host.contains("netbsd") || + host.contains("openbsd") { + + make = "gmake" + } + + let configure = src.join("src/libbacktrace/configure").into_os_string(); + + // When cross-compiling on Windows, this path will contain backslashes, + // but configure doesn't like that. Replace them with forward slashes. + #[cfg(windows)] + let configure = { + use std::os::windows::ffi::{OsStrExt, OsStringExt}; + let mut chars: Vec = configure.encode_wide().collect(); + for c in chars.iter_mut() { + if *c == '\\' as u16 { + *c = '/' as u16; + } + } + OsString::from_wide(&chars) + }; + + let cfg = cc::Build::new(); + let compiler = cfg.get_compiler(); + let cc = compiler.path().file_name().unwrap().to_str().unwrap(); + let mut flags = OsString::new(); + for (i, flag) in compiler.args().iter().enumerate() { + if i > 0 { + flags.push(" "); + } + flags.push(flag); + } + let ar = find_tool(&compiler, cc, "ar"); + let ranlib = find_tool(&compiler, cc, "ranlib"); + let mut cmd = Command::new("sh"); + + cmd.arg(configure) + .current_dir(&dst) + .env("AR", &ar) + .env("RANLIB", &ranlib) + .env("CC", compiler.path()) + .env("CFLAGS", flags) + .arg("--with-pic") + .arg("--disable-multilib") + .arg("--disable-shared") + .arg("--disable-host-shared") + .arg(format!("--host={}", target)); + + // Apparently passing this flag causes problems on Windows + if !host.contains("windows") { + cmd.arg(format!("--build={}", host)); + } + + run(&mut cmd, "sh"); + let mut cmd = Command::new(make); + if let Some(makeflags) = env::var_os("CARGO_MAKEFLAGS") { + cmd.env("MAKEFLAGS", makeflags); + } + + run(cmd.current_dir(&dst) + .arg(format!("INCDIR={}", + src.join("src/libbacktrace").display())), + "make"); + + println!("cargo:rustc-link-search=native={}/.libs", dst.display()); + println!("cargo:rustc-link-lib=static=backtrace"); + + // The standard library currently bundles in libbacktrace, but it's + // compiled with hidden visibility (naturally) so we can't use it. + // + // To prevent conflicts with a second statically linked copy we rename all + // symbols with a '__rbt_' prefix manually here through `objcopy`. + let lib = dst.join(".libs/libbacktrace.a"); + let tmpdir = dst.join("__tmp"); + drop(fs::remove_dir_all(&tmpdir)); + t!(fs::create_dir_all(&tmpdir)); + run(Command::new(&ar).arg("x").arg(&lib).current_dir(&tmpdir), + ar.to_str().unwrap()); + + t!(fs::remove_file(&lib)); + let mut objs = Vec::new(); + let objcopy = find_tool(&compiler, cc, "objcopy"); + for obj in t!(tmpdir.read_dir()) { + let obj = t!(obj); + run(Command::new(&objcopy) + .arg("--redefine-syms=symbol-map") + .arg(obj.path()), + objcopy.to_str().unwrap()); + objs.push(obj.path()); + } + + run(Command::new(&ar).arg("crus").arg(&lib).args(&objs), + ar.to_str().unwrap()); +} + +fn run(cmd: &mut Command, program: &str) { + println!("running: {:?}", cmd); + let status = match cmd.status() { + Ok(s) => s, + Err(ref e) if e.kind() == io::ErrorKind::NotFound => { + panic!("\n\nfailed to execute command: {}\nIs `{}` \ + not installed?\n\n", + e, + program); + } + Err(e) => panic!("failed to get status: {}", e), + }; + if !status.success() { + panic!("failed with: {}", status); + } +} diff --git a/backtrace-sys-0.1.16/src/lib.rs b/backtrace-sys-0.1.16/src/lib.rs new file mode 100644 index 000000000..0edc2674c --- /dev/null +++ b/backtrace-sys-0.1.16/src/lib.rs @@ -0,0 +1,44 @@ +#![allow(bad_style)] + +extern crate libc; + +use libc::uintptr_t; +use std::os::raw::{c_void, c_char, c_int}; + +pub type backtrace_syminfo_callback = + extern fn(data: *mut c_void, + pc: uintptr_t, + symname: *const c_char, + symval: uintptr_t, + symsize: uintptr_t); +pub type backtrace_full_callback = + extern fn(data: *mut c_void, + pc: uintptr_t, + filename: *const c_char, + lineno: c_int, + function: *const c_char) -> c_int; +pub type backtrace_error_callback = + extern fn(data: *mut c_void, + msg: *const c_char, + errnum: c_int); +pub enum backtrace_state {} + +extern { + #[link_name = "__rbt_backtrace_create_state"] + pub fn backtrace_create_state(filename: *const c_char, + threaded: c_int, + error: backtrace_error_callback, + data: *mut c_void) -> *mut backtrace_state; + #[link_name = "__rbt_backtrace_syminfo"] + pub fn backtrace_syminfo(state: *mut backtrace_state, + addr: uintptr_t, + cb: backtrace_syminfo_callback, + error: backtrace_error_callback, + data: *mut c_void) -> c_int; + #[link_name = "__rbt_backtrace_pcinfo"] + pub fn backtrace_pcinfo(state: *mut backtrace_state, + addr: uintptr_t, + cb: backtrace_full_callback, + error: backtrace_error_callback, + data: *mut c_void) -> c_int; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/ChangeLog b/backtrace-sys-0.1.16/src/libbacktrace/ChangeLog new file mode 100644 index 000000000..88005dfb0 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/ChangeLog @@ -0,0 +1,598 @@ +2016-11-15 Matthias Klose + + * configure: Regenerate. + +2016-09-11 Carlos Liam + + * all: Remove meaningless trailing whitespace. + +2016-05-18 Uros Bizjak + + PR target/71161 + * elf.c (phdr_callback) [__i386__]: Add + __attribute__((__force_align_arg_pointer__)). + +2016-03-02 Maxim Ostapenko + + * elf.c (backtrace_initialize): Properly initialize elf_fileline_fn to + avoid possible crash. + (elf_add): Don't set *fileline_fn to elf_nodebug value in case of + missing debug info anymore. + +2016-02-06 John David Anglin + + * mmap.c (MAP_FAILED): Define if not defined. + +2016-01-04 Jakub Jelinek + + Update copyright years. + +2015-12-18 Andris Pavenis + + * configure.ac: Specify that DJGPP do not have mmap + even when sys/mman.h exists. + * configure: Regenerate + +2015-12-09 John David Anglin + + PR libgfortran/68115 + * configure.ac: Set libbacktrace_cv_sys_sync to no on hppa*-*-hpux*. + * configure: Regenerate. + * elf.c (backtrace_initialize): Cast __sync_bool_compare_and_swap call + to void. + +2015-09-17 Ian Lance Taylor + + * posix.c (backtrace_open): Cast second argument of open() to int. + +2015-09-11 Ian Lance Taylor + + * Makefile.am (backtrace.lo): Depend on internal.h. + (sort.lo, stest.lo): Add explicit dependencies. + * Makefile.in: Rebuild. + +2015-09-09 Hans-Peter Nilsson + + * backtrace.c: #include . + +2015-09-08 Ian Lance Taylor + + PR other/67457 + * backtrace.c: #include "internal.h". + (struct backtrace_data): Add can_alloc field. + (unwind): If can_alloc is false, don't try to get file/line + information. + (backtrace_full): Set can_alloc field in bdata. + * alloc.c (backtrace_alloc): Don't call error_callback if it is + NULL. + * mmap.c (backtrace_alloc): Likewise. + * internal.h: Update comments for backtrace_alloc and + backtrace_free. + +2015-09-08 Ian Lance Taylor + + PR other/67457 + * mmap.c (backtrace_alloc): Correct test for mmap failure. + +2015-08-31 Ulrich Weigand + + * configure.ac: For spu-*-* targets, set have_fcntl to no. + * configure: Regenerate. + +2015-08-27 Ulrich Weigand + + * configure.ac: Remove [disable-shared] argument to LT_INIT. + Remove setting PIC_FLAG when building as target library. + * configure: Regenerate. + +2015-08-26 Hans-Peter Nilsson + + * configure.ac: Only compile with -fPIC if the target + supports it. + * configure: Regenerate. + +2015-08-24 Ulrich Weigand + + * configure.ac: Set have_mmap to no on spu-*-* targets. + * configure: Regenerate. + +2015-08-13 Ian Lance Taylor + + * dwarf.c (read_function_entry): Add vec_inlined parameter. + Change all callers. + +2015-06-11 Martin Sebor + + PR sanitizer/65479 + * dwarf.c (struct line): Add new field idx. + (line_compare): Use it. + (add_line): Set it. + (read_line_info): Reset it. + +2015-05-29 Tristan Gingold + + * pecoff.c: New file. + * Makefile.am (FORMAT_FILES): Add pecoff.c and dependencies. + * Makefile.in: Regenerate. + * filetype.awk: Detect pecoff. + * configure.ac: Define BACKTRACE_SUPPORTS_DATA on elf platforms. + Add pecoff. + * btest.c (test5): Test enabled only if BACKTRACE_SUPPORTS_DATA is + true. + * backtrace-supported.h.in (BACKTRACE_SUPPORTS_DATA): Define. + * configure: Regenerate. + * pecoff.c: New file. + +2015-05-13 Michael Haubenwallner + + * Makefile.in: Regenerated with automake-1.11.6. + * aclocal.m4: Likewise. + * configure: Likewise. + +2015-01-24 Matthias Klose + + * configure.ac: Move AM_ENABLE_MULTILIB before AC_PROG_CC. + * configure: Regenerate. + +2015-01-05 Jakub Jelinek + + Update copyright years. + +2014-11-21 H.J. Lu + + PR bootstrap/63784 + * configure: Regenerated. + +2014-11-11 David Malcolm + + * ChangeLog.jit: New. + +2014-11-11 Francois-Xavier Coudert + + PR target/63610 + * configure: Regenerate. + +2014-10-23 Ian Lance Taylor + + * internal.h (backtrace_atomic_load_pointer) [no atomic or sync]: + Fix to return void *. + +2014-05-08 Ian Lance Taylor + + * mmap.c (backtrace_free): If freeing a large aligned block of + memory, call munmap rather than holding onto it. + (backtrace_vector_grow): When growing a vector, double the number + of pages requested. When releasing the old version of a grown + vector, pass the correct size to backtrace_free. + +2014-03-07 Ian Lance Taylor + + * sort.c (backtrace_qsort): Use middle element as pivot. + +2014-03-06 Ian Lance Taylor + + * sort.c: New file. + * stest.c: New file. + * internal.h (backtrace_qsort): Declare. + * dwarf.c (read_abbrevs): Call backtrace_qsort instead of qsort. + (read_line_info, read_function_entry): Likewise. + (read_function_info, build_dwarf_data): Likewise. + * elf.c (elf_initialize_syminfo): Likewise. + * Makefile.am (libbacktrace_la_SOURCES): Add sort.c. + (stest_SOURCES, stest_LDADD): Define. + (check_PROGRAMS): Add stest. + +2014-02-07 Misty De Meo + + PR target/58710 + * configure.ac: Use AC_LINK_IFELSE in check for + _Unwind_GetIPInfo. + * configure: Regenerate. + +2014-01-02 Richard Sandiford + + Update copyright years + +2013-12-06 Jakub Jelinek + + * elf.c (ET_DYN): Undefine and define again. + (elf_add): Add exe argument, if true and ehdr.e_type is ET_DYN, + return early -1 without closing the descriptor. + (struct phdr_data): Add exe_descriptor. + (phdr_callback): If pd->exe_descriptor is not -1, for very first + call if dlpi_name is NULL just call elf_add with the exe_descriptor, + otherwise backtrace_close the exe_descriptor if not -1. Adjust + call to elf_add. + (backtrace_initialize): Adjust call to elf_add. If it returns + -1, set pd.exe_descriptor to descriptor, otherwise set it to -1. + +2013-12-05 Ian Lance Taylor + + * alloc.c (backtrace_vector_finish): Add error_callback and data + parameters. Call backtrace_vector_release. Return address base. + * mmap.c (backtrace_vector_finish): Add error_callback and data + parameters. Return address base. + * dwarf.c (read_function_info): Get new address base from + backtrace_vector_finish. + * internal.h (backtrace_vector_finish): Update declaration. + +2013-11-27 Ian Lance Taylor + + * dwarf.c (find_address_ranges): New static function, broken out + of build_address_map. + (build_address_map): Call it. + * btest.c (check): Check for missing filename or function, rather + than crashing. + (f3): Check that enough frames were returned. + +2013-11-19 Jakub Jelinek + + * backtrace.h (backtrace_syminfo_callback): Add symsize argument. + * elf.c (elf_syminfo): Pass 0 or sym->size to the callback as + last argument. + * btest.c (struct symdata): Add size field. + (callback_three): Add symsize argument. Copy it to the data->size + field. + (f23): Set symdata.size to 0. + (test5): Likewise. If sizeof (int) > 1, lookup address of + ((uintptr_t) &global) + 1. Verify symdata.val and symdata.size + values. + + * atomic.c: Include sys/types.h. + +2013-11-18 Ian Lance Taylor + + * configure.ac: Check for support of __atomic extensions. + * internal.h: Declare or #define atomic functions for use in + backtrace code. + * atomic.c: New file. + * dwarf.c (dwarf_lookup_pc): Use atomic functions. + (dwarf_fileline, backtrace_dwarf_add): Likewise. + * elf.c (elf_add_syminfo_data, elf_syminfo): Likewise. + (backtrace_initialize): Likewise. + * fileline.c (fileline_initialize): Likewise. + * Makefile.am (libbacktrace_la_SOURCES): Add atomic.c. + * configure, config.h.in, Makefile.in: Rebuild. + +2013-11-18 Jakub Jelinek + + * elf.c (SHN_UNDEF): Define. + (elf_initialize_syminfo): Add base_address argument. Ignore symbols + with st_shndx == SHN_UNDEF. Add base_address to address fields. + (elf_add): Adjust caller. + + * elf.c (phdr_callback): Process info->dlpi_addr == 0 normally. + +2013-11-16 Ian Lance Taylor + + * backtrace.h (backtrace_create_state): Correct comment about + threading. + +2013-11-15 Ian Lance Taylor + + * backtrace.h (backtrace_syminfo): Update comment and parameter + name to take any address, not just a PC value. + * elf.c (STT_OBJECT): Define. + (elf_nosyms): Rename parameter pc to addr. + (elf_symbol_search): Rename local variable pc to addr. + (elf_initialize_syminfo): Add STT_OBJECT symbols to elf_symbols. + (elf_syminfo): Rename parameter pc to addr. + * btest.c (global): New global variable. + (test5): New test. + (main): Call test5. + +2013-10-17 Ian Lance Taylor + + * elf.c (elf_add): Don't get the wrong offsets if a debug section + is missing. + +2013-10-15 David Malcolm + + * configure.ac: Add --enable-host-shared, setting up + pre-existing PIC_FLAG variable within Makefile.am et al. + * configure: Regenerate. + +2013-09-20 Alan Modra + + * configure: Regenerate. + +2013-07-23 Alexander Monakov + + * elf.c (elf_syminfo): Loop over the elf_syminfo_data chain. + +2013-07-23 Alexander Monakov + + * elf.c (backtrace_initialize): Pass elf_fileline_fn to + dl_iterate_phdr callbacks. + +2013-03-25 Ian Lance Taylor + + * alloc.c: #include . + * mmap.c: Likewise. + +2013-01-31 Ian Lance Taylor + + * dwarf.c (read_function_info): Permit fvec parameter to be NULL. + (dwarf_lookup_pc): Don't use ddata->fvec if threaded. + +2013-01-25 Jakub Jelinek + + PR other/56076 + * dwarf.c (read_line_header): Don't crash if DW_AT_comp_dir + attribute was not seen. + +2013-01-16 Ian Lance Taylor + + * dwarf.c (struct unit): Add filename and abs_filename fields. + (build_address_map): Set new fields when reading unit. + (dwarf_lookup_pc): If we don't find an entry in the line table, + just return the main file name. + +2013-01-14 Richard Sandiford + + Update copyright years. + +2013-01-01 Ian Lance Taylor + + PR bootstrap/54834 + * Makefile.am (AM_CPPFLAGS): Remove -I ../gcc/include and -I + $(MULTIBUILDTOP)/../../gcc/include. + * Makefile.in: Rebuild. + +2013-01-01 Ian Lance Taylor + + PR other/55536 + * mmap.c (backtrace_alloc): Don't call sync functions if not + threaded. + (backtrace_free): Likewise. + +2012-12-12 John David Anglin + + * mmapio.c: Define MAP_FAILED if not defined. + +2012-12-11 Jakub Jelinek + + PR bootstrap/54926 + * Makefile.am (AM_CFLAGS): Remove -frandom-seed=$@. + * configure.ac: If --with-target-subdir, add -frandom-seed=$@ + to EXTRA_FLAGS unconditionally, otherwise check whether the compiler + accepts it. + * Makefile.in: Regenerated. + * configure: Regenerated. + +2012-12-07 Jakub Jelinek + + PR bootstrap/54926 + * Makefile.am (AM_CFLAGS): Add -frandom-seed=$@. + * Makefile.in: Regenerated. + +2012-11-20 Ian Lance Taylor + + * dwarf.c (read_attribute): Always clear val. + +2012-11-13 Ian Lance Taylor + + PR other/55312 + * configure.ac: Only add -Werror if building a target library. + * configure: Rebuild. + +2012-11-12 Ian Lance Taylor + Rainer Orth + Gerald Pfeifer + + * configure.ac: Check for getexecname. + * fileline.c: #include . Define getexecname if not + available. + (fileline_initialize): Try to find the executable in a few + different ways. + * print.c (error_callback): Only print the filename if it came + from the backtrace state. + * configure, config.h.in: Rebuild. + +2012-10-29 Ian Lance Taylor + + * mmap.c (backtrace_vector_release): Correct last patch: add + aligned, not size. + +2012-10-29 Ian Lance Taylor + + * mmap.c (backtrace_vector_release): Make sure freed block is + aligned on 8-byte boundary. + +2012-10-26 Ian Lance Taylor + + PR other/55087 + * posix.c (backtrace_open): Add does_not_exist parameter. + * elf.c (phdr_callback): Do not warn if shared library could not + be opened. + * fileline.c (fileline_initialize): Update calls to + backtrace_open. + * internal.h (backtrace_open): Update declaration. + +2012-10-26 Jack Howarth + + PR target/55061 + * configure.ac: Check for _Unwind_GetIPInfo function declaration. + * configure: Regenerate. + +2012-10-24 Ian Lance Taylor + + PR target/55061 + * configure.ac: Check whether -funwind-tables option works. + * configure: Rebuild. + +2012-10-11 Ian Lance Taylor + + * configure.ac: Do not use dl_iterate_phdr on Solaris 10. + * configure: Rebuild. + +2012-10-10 Ian Lance Taylor + + * elf.c: Rename all Elf typedefs to start with b_elf, and be all + lower case. + +2012-10-10 Hans-Peter Nilsson + + * elf.c (elf_add_syminfo_data): Add casts to avoid warning. + +2012-10-09 Ian Lance Taylor + + * dwarf.c (dwarf_fileline): Add cast to avoid warning. + (backtrace_dwarf_add): Likewise. + +2012-10-09 Ian Lance Taylor + + Add support for tracing through shared libraries. + * configure.ac: Check for link.h and dl_iterate_phdr. + * elf.c: #include if system has dl_iterate_phdr. #undef + ELF macros before #defining them. + (dl_phdr_info, dl_iterate_phdr): Define if system does not have + dl_iterate_phdr. + (struct elf_syminfo_data): Add next field. + (elf_initialize_syminfo): Initialize next field. + (elf_add_syminfo_data): New static function. + (elf_add): New static function, broken out of + backtrace_initialize. Call backtrace_dwarf_add instead of + backtrace_dwarf_initialize. + (struct phdr_data): Define. + (phdr_callback): New static function. + (backtrace_initialize): Call elf_add. + * dwarf.c (struct dwarf_data): Add next and base_address fields. + (add_unit_addr): Add base_address parameter. Change all callers. + (add_unit_ranges, build_address_map): Likewise. + (add_line): Add ddata parameter. Change all callers. + (read_line_program, add_function_range): Likewise. + (dwarf_lookup_pc): New static function, broken out of + dwarf_fileline. + (dwarf_fileline): Call dwarf_lookup_pc. + (build_dwarf_data): New static function. + (backtrace_dwarf_add): New function. + (backtrace_dwarf_initialize): Remove. + * internal.h (backtrace_dwarf_initialize): Don't declare. + (backtrace_dwarf_add): Declare. + * configure, config.h.in: Rebuild. + +2012-10-04 Gerald Pfeifer + + * btest.c (f23): Avoid uninitialized variable warning. + +2012-10-04 Ian Lance Taylor + + * dwarf.c: If the system header files do not declare strnlen, + provide our own version. + +2012-10-03 Ian Lance Taylor + + * dwarf.c (read_uleb128): Fix overflow test. + (read_sleb128): Likewise. + (build_address_map): Don't change unit_buf.start. + +2012-10-02 Uros Bizjak + + PR other/54761 + * configure.ac (EXTRA_FLAGS): New. + * Makefile.am (AM_FLAGS): Add $(EXTRA_FLAGS). + * configure, Makefile.in: Regenerate. + +2012-09-29 Ian Lance Taylor + + PR other/54749 + * fileline.c (fileline_initialize): Pass errnum as -1 when + reporting that we could not read executable information after a + previous failure. + +2012-09-27 Ian Lance Taylor + + PR bootstrap/54732 + * configure.ac: Add no-dependencies to AM_INIT_AUTOMAKE. + * Makefile.am: Add dependencies for all objects. + * configure, aclocal.m4, Makefile.in: Rebuild. + +2012-09-27 Ian Lance Taylor + + PR other/54726 + * elf.c (backtrace_initialize): Set *fileln_fn, not + state->fileln_fn. + +2012-09-19 Ian Lance Taylor + + * configure.ac: Only use GCC_CHECK_UNWIND_GETIPINFO when compiled + as a target library. + * configure: Rebuild. + +2012-09-19 Rainer Orth + Ian Lance Taylor + + * configure.ac (GCC_HEADER_STDINT): Invoke. + * backtrace.h: If we can't find , use "gstdint.h". + * btest.c: Don't include . + * dwarf.c: Likewise. + * configure, aclocal.m4, Makefile.in, config.h.in: Rebuild. + +2012-09-18 Ian Lance Taylor + + PR bootstrap/54623 + * Makefile.am (AM_CPPFLAGS): Define. + (AM_CFLAGS): Remove -I options. + * Makefile.in: Rebuild. + +2012-09-18 Ian Lance Taylor + + * posix.c (O_BINARY): Define if not defined. + (backtrace_open): Pass O_BINARY to open. Only call fcntl if + HAVE_FCNTL is defined. + * configure.ac: Test for the fcntl function. + * configure, config.h.in: Rebuild. + +2012-09-18 Ian Lance Taylor + + * btest.c (test1, test2, test3, test4): Add the unused attribute. + +2012-09-18 Ian Lance Taylor + + * dwarf.c: Correct test of HAVE_DECL_STRNLEN. + +2012-09-18 Ian Lance Taylor + + * configure.ac: Add AC_USE_SYSTEM_EXTENSIONS. + * mmapio.c: Don't define _GNU_SOURCE. + * configure, config.h.in: Rebuild. + +2012-09-18 Ian Lance Taylor + + * configure.ac: Check whether strnlen is declared. + * dwarf.c: Declare strnlen if not declared. + * configure, config.h.in: Rebuild. + +2012-09-18 Rainer Orth + + * fileline.c: Include . + * mmap.c: Likewise. + +2012-09-17 Ian Lance Taylor + + PR bootstrap/54611 + * nounwind.c (backtrace_full): Rename from backtrace. Add state + parameter. + +2012-09-17 Gerald Pfeifer + + PR bootstrap/54611 + * nounwind.c (backtrace_simple): Add state parameter. + +2012-09-17 Ian Lance Taylor + + PR bootstrap/54609 + * unknown.c (unknown_fileline): Add state parameter, remove + fileline_data parameter, name error_callback parameter. + (backtrace_initialize): Add state parameter. + +2012-09-17 Ian Lance Taylor + + * Initial implementation. + +Copyright (C) 2012-2016 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/backtrace-sys-0.1.16/src/libbacktrace/ChangeLog.jit b/backtrace-sys-0.1.16/src/libbacktrace/ChangeLog.jit new file mode 100644 index 000000000..6b60e3b3b --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/ChangeLog.jit @@ -0,0 +1,14 @@ +2014-09-24 David Malcolm + + * ChangeLog.jit: Add copyright footer. + +2013-10-03 David Malcolm + + * configure.ac: Add --enable-host-shared. + * configure: Regenerate. + +Copyright (C) 2013-2014 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/backtrace-sys-0.1.16/src/libbacktrace/Makefile.am b/backtrace-sys-0.1.16/src/libbacktrace/Makefile.am new file mode 100644 index 000000000..61aec4474 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/Makefile.am @@ -0,0 +1,136 @@ +# Makefile.am -- Backtrace Makefile. +# Copyright (C) 2012-2016 Free Software Foundation, Inc. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: + +# (1) Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. + +# (2) Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. + +# (3) The name of the author may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +ACLOCAL_AMFLAGS = -I .. -I ../config + +AM_CPPFLAGS = -I $(top_srcdir)/../include -I $(top_srcdir)/../libgcc \ + -I ../libgcc + +AM_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) $(PIC_FLAG) + +noinst_LTLIBRARIES = libbacktrace.la + +libbacktrace_la_SOURCES = \ + backtrace.h \ + atomic.c \ + dwarf.c \ + fileline.c \ + internal.h \ + posix.c \ + print.c \ + sort.c \ + state.c + +BACKTRACE_FILES = \ + backtrace.c \ + simple.c \ + nounwind.c + +FORMAT_FILES = \ + elf.c \ + pecoff.c \ + unknown.c + +VIEW_FILES = \ + read.c \ + mmapio.c + +ALLOC_FILES = \ + alloc.c \ + mmap.c + +EXTRA_libbacktrace_la_SOURCES = \ + $(BACKTRACE_FILES) \ + $(FORMAT_FILES) \ + $(VIEW_FILES) \ + $(ALLOC_FILES) + +libbacktrace_la_LIBADD = \ + $(BACKTRACE_FILE) \ + $(FORMAT_FILE) \ + $(VIEW_FILE) \ + $(ALLOC_FILE) + +libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD) + +# Testsuite. + +check_PROGRAMS = + +TESTS = $(check_PROGRAMS) + +if NATIVE + +btest_SOURCES = btest.c +btest_CFLAGS = $(AM_CFLAGS) -g -O +btest_LDADD = libbacktrace.la + +check_PROGRAMS += btest + +stest_SOURCES = stest.c +stest_LDADD = libbacktrace.la + +check_PROGRAMS += stest + +endif NATIVE + +# We can't use automake's automatic dependency tracking, because it +# breaks when using bootstrap-lean. Automatic dependency tracking +# with GCC bootstrap will cause some of the objects to depend on +# header files in prev-gcc/include, e.g., stddef.h and stdarg.h. When +# using bootstrap-lean, prev-gcc is removed after each stage. When +# running "make install", those header files will be gone, causing the +# library to be rebuilt at install time. That may not succeed. + +# These manual dependencies do not include dependencies on unwind.h, +# even though that is part of GCC, because where to find it depends on +# whether we are being built as a host library or a target library. + +INCDIR = $(top_srcdir)/../include +alloc.lo: config.h backtrace.h internal.h +backtrace.lo: config.h backtrace.h internal.h +btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h +dwarf.lo: config.h $(INCDIR)/dwarf2.h $(INCDIR)/dwarf2.def \ + $(INCDIR)/filenames.h backtrace.h internal.h +elf.lo: config.h backtrace.h internal.h +fileline.lo: config.h backtrace.h internal.h +mmap.lo: config.h backtrace.h internal.h +mmapio.lo: config.h backtrace.h internal.h +nounwind.lo: config.h internal.h +pecoff.lo: config.h backtrace.h internal.h +posix.lo: config.h backtrace.h internal.h +print.lo: config.h backtrace.h internal.h +read.lo: config.h backtrace.h internal.h +simple.lo: config.h backtrace.h internal.h +sort.lo: config.h backtrace.h internal.h +stest.lo: config.h backtrace.h internal.h +state.lo: config.h backtrace.h backtrace-supported.h internal.h +unknown.lo: config.h backtrace.h internal.h diff --git a/backtrace-sys-0.1.16/src/libbacktrace/Makefile.in b/backtrace-sys-0.1.16/src/libbacktrace/Makefile.in new file mode 100644 index 000000000..de74b5d09 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/Makefile.in @@ -0,0 +1,770 @@ +# Makefile.in generated by automake 1.11.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am -- Backtrace Makefile. +# Copyright (C) 2012-2016 Free Software Foundation, Inc. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: + +# (1) Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. + +# (2) Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. + +# (3) The name of the author may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +check_PROGRAMS = $(am__EXEEXT_1) +@NATIVE_TRUE@am__append_1 = btest stest +subdir = . +DIST_COMMON = README ChangeLog $(srcdir)/Makefile.in \ + $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(srcdir)/config.h.in \ + $(srcdir)/../mkinstalldirs $(srcdir)/backtrace-supported.h.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/../config/lead-dot.m4 \ + $(top_srcdir)/../config/multi.m4 \ + $(top_srcdir)/../config/override.m4 \ + $(top_srcdir)/../config/stdint.m4 \ + $(top_srcdir)/../config/unwind_ipinfo.m4 \ + $(top_srcdir)/../config/warnings.m4 \ + $(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \ + $(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \ + $(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = backtrace-supported.h +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +am__DEPENDENCIES_1 = +am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \ + print.lo sort.lo state.lo +libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS) +@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT) +@NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) +btest_OBJECTS = $(am_btest_OBJECTS) +@NATIVE_TRUE@btest_DEPENDENCIES = libbacktrace.la +btest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +@NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT) +stest_OBJECTS = $(am_stest_OBJECTS) +@NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = +am__depfiles_maybe = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \ + $(btest_SOURCES) $(stest_SOURCES) +MULTISRCTOP = +MULTIBUILDTOP = +MULTIDIRS = +MULTISUBDIR = +MULTIDO = true +MULTICLEAN = true +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +ACLOCAL = @ACLOCAL@ +ALLOC_FILE = @ALLOC_FILE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BACKTRACE_FILE = @BACKTRACE_FILE@ +BACKTRACE_SUPPORTED = @BACKTRACE_SUPPORTED@ +BACKTRACE_SUPPORTS_DATA = @BACKTRACE_SUPPORTS_DATA@ +BACKTRACE_SUPPORTS_THREADS = @BACKTRACE_SUPPORTS_THREADS@ +BACKTRACE_USES_MALLOC = @BACKTRACE_USES_MALLOC@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +EXTRA_FLAGS = @EXTRA_FLAGS@ +FGREP = @FGREP@ +FORMAT_FILE = @FORMAT_FILE@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIC_FLAG = @PIC_FLAG@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +VIEW_FILE = @VIEW_FILE@ +WARN_FLAGS = @WARN_FLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__leading_dot = @am__leading_dot@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libtool_VERSION = @libtool_VERSION@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +multi_basedir = @multi_basedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +ACLOCAL_AMFLAGS = -I .. -I ../config +AM_CPPFLAGS = -I $(top_srcdir)/../include -I $(top_srcdir)/../libgcc \ + -I ../libgcc + +AM_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) $(PIC_FLAG) +noinst_LTLIBRARIES = libbacktrace.la +libbacktrace_la_SOURCES = \ + backtrace.h \ + atomic.c \ + dwarf.c \ + fileline.c \ + internal.h \ + posix.c \ + print.c \ + sort.c \ + state.c + +BACKTRACE_FILES = \ + backtrace.c \ + simple.c \ + nounwind.c + +FORMAT_FILES = \ + elf.c \ + pecoff.c \ + unknown.c + +VIEW_FILES = \ + read.c \ + mmapio.c + +ALLOC_FILES = \ + alloc.c \ + mmap.c + +EXTRA_libbacktrace_la_SOURCES = \ + $(BACKTRACE_FILES) \ + $(FORMAT_FILES) \ + $(VIEW_FILES) \ + $(ALLOC_FILES) + +libbacktrace_la_LIBADD = \ + $(BACKTRACE_FILE) \ + $(FORMAT_FILE) \ + $(VIEW_FILE) \ + $(ALLOC_FILE) + +libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD) +TESTS = $(check_PROGRAMS) +@NATIVE_TRUE@btest_SOURCES = btest.c +@NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O +@NATIVE_TRUE@btest_LDADD = libbacktrace.la +@NATIVE_TRUE@stest_SOURCES = stest.c +@NATIVE_TRUE@stest_LDADD = libbacktrace.la + +# We can't use automake's automatic dependency tracking, because it +# breaks when using bootstrap-lean. Automatic dependency tracking +# with GCC bootstrap will cause some of the objects to depend on +# header files in prev-gcc/include, e.g., stddef.h and stdarg.h. When +# using bootstrap-lean, prev-gcc is removed after each stage. When +# running "make install", those header files will be gone, causing the +# library to be rebuilt at install time. That may not succeed. + +# These manual dependencies do not include dependencies on unwind.h, +# even though that is part of GCC, because where to find it depends on +# whether we are being built as a host library or a target library. +INCDIR = $(top_srcdir)/../include +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @if test ! -f $@; then rm -f stamp-h1; else :; fi + @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +backtrace-supported.h: $(top_builddir)/config.status $(srcdir)/backtrace-supported.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EXTRA_libbacktrace_la_DEPENDENCIES) + $(LINK) $(libbacktrace_la_OBJECTS) $(libbacktrace_la_LIBADD) $(LIBS) + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES) + @rm -f btest$(EXEEXT) + $(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS) +stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES) + @rm -f stest$(EXEEXT) + $(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(COMPILE) -c $< + +.c.obj: + $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: + $(LTCOMPILE) -c -o $@ $< + +btest-btest.o: btest.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c + +btest-btest.obj: btest.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt + +# GNU Make needs to see an explicit $(MAKE) variable in the command it +# runs to enable its job server during parallel builds. Hence the +# comments below. +all-multi: + $(MULTIDO) $(AM_MAKEFLAGS) DO=all multi-do # $(MAKE) +install-multi: + $(MULTIDO) $(AM_MAKEFLAGS) DO=install multi-do # $(MAKE) + +mostlyclean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=mostlyclean multi-clean # $(MAKE) +clean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=clean multi-clean # $(MAKE) +distclean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=distclean multi-clean # $(MAKE) +maintainer-clean-multi: + $(MULTICLEAN) $(AM_MAKEFLAGS) DO=maintainer-clean multi-clean # $(MAKE) + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile $(LTLIBRARIES) all-multi config.h +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am clean-multi + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-am distclean-multi + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-multi + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am maintainer-clean-multi + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am mostlyclean-multi + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: all all-multi check-am clean-multi distclean-multi install-am \ + install-multi install-strip maintainer-clean-multi \ + mostlyclean-multi + +.PHONY: CTAGS GTAGS all all-am all-multi am--refresh check check-TESTS \ + check-am clean clean-checkPROGRAMS clean-generic clean-libtool \ + clean-multi clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-hdr \ + distclean-libtool distclean-multi distclean-tags dvi dvi-am \ + html html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-multi install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic maintainer-clean-multi mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + mostlyclean-multi pdf pdf-am ps ps-am tags uninstall \ + uninstall-am + +alloc.lo: config.h backtrace.h internal.h +backtrace.lo: config.h backtrace.h internal.h +btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h +dwarf.lo: config.h $(INCDIR)/dwarf2.h $(INCDIR)/dwarf2.def \ + $(INCDIR)/filenames.h backtrace.h internal.h +elf.lo: config.h backtrace.h internal.h +fileline.lo: config.h backtrace.h internal.h +mmap.lo: config.h backtrace.h internal.h +mmapio.lo: config.h backtrace.h internal.h +nounwind.lo: config.h internal.h +pecoff.lo: config.h backtrace.h internal.h +posix.lo: config.h backtrace.h internal.h +print.lo: config.h backtrace.h internal.h +read.lo: config.h backtrace.h internal.h +simple.lo: config.h backtrace.h internal.h +sort.lo: config.h backtrace.h internal.h +stest.lo: config.h backtrace.h internal.h +state.lo: config.h backtrace.h backtrace-supported.h internal.h +unknown.lo: config.h backtrace.h internal.h + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/backtrace-sys-0.1.16/src/libbacktrace/README b/backtrace-sys-0.1.16/src/libbacktrace/README new file mode 100644 index 000000000..e8b225745 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/README @@ -0,0 +1,23 @@ +The libbacktrace library +Initially written by Ian Lance Taylor + +The libbacktrace library may be linked into a program or library and +used to produce symbolic backtraces. Sample uses would be to print a +detailed backtrace when an error occurs or to gather detailed +profiling information. + +The libbacktrace library is provided under a BSD license. See the +source files for the exact license text. + +The public functions are declared and documented in the header file +backtrace.h, which should be #include'd by a user of the library. + +Building libbacktrace will generate a file backtrace-supported.h, +which a user of the library may use to determine whether backtraces +will work. See the source file backtrace-supported.h.in for the +macros that it defines. + +As of September 2012, libbacktrace only supports ELF executables with +DWARF debugging information. The library is written to make it +straightforward to add support for other object file and debugging +formats. diff --git a/backtrace-sys-0.1.16/src/libbacktrace/aclocal.m4 b/backtrace-sys-0.1.16/src/libbacktrace/aclocal.m4 new file mode 100644 index 000000000..8e84ddd1f --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/aclocal.m4 @@ -0,0 +1,683 @@ +# generated automatically by aclocal 1.11.6 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, +# Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.64],, +[m4_warning([this file was generated for autoconf 2.64. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software +# Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.6], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.6])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation, +# Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008, +# 2011 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless `enable' is passed literally. +# For symmetry, `disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], +[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation, +# Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software +# Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([../config/lead-dot.m4]) +m4_include([../config/multi.m4]) +m4_include([../config/override.m4]) +m4_include([../config/stdint.m4]) +m4_include([../config/unwind_ipinfo.m4]) +m4_include([../config/warnings.m4]) +m4_include([../libtool.m4]) +m4_include([../ltoptions.m4]) +m4_include([../ltsugar.m4]) +m4_include([../ltversion.m4]) +m4_include([../lt~obsolete.m4]) diff --git a/backtrace-sys-0.1.16/src/libbacktrace/alloc.c b/backtrace-sys-0.1.16/src/libbacktrace/alloc.c new file mode 100644 index 000000000..3333624a2 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/alloc.c @@ -0,0 +1,156 @@ +/* alloc.c -- Memory allocation without mmap. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +/* Allocation routines to use on systems that do not support anonymous + mmap. This implementation just uses malloc, which means that the + backtrace functions may not be safely invoked from a signal + handler. */ + +/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't + report an error. */ + +void * +backtrace_alloc (struct backtrace_state *state ATTRIBUTE_UNUSED, + size_t size, backtrace_error_callback error_callback, + void *data) +{ + void *ret; + + ret = malloc (size); + if (ret == NULL) + { + if (error_callback) + error_callback (data, "malloc", errno); + } + return ret; +} + +/* Free memory. */ + +void +backtrace_free (struct backtrace_state *state ATTRIBUTE_UNUSED, + void *p, size_t size ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + free (p); +} + +/* Grow VEC by SIZE bytes. */ + +void * +backtrace_vector_grow (struct backtrace_state *state ATTRIBUTE_UNUSED, + size_t size, backtrace_error_callback error_callback, + void *data, struct backtrace_vector *vec) +{ + void *ret; + + if (size > vec->alc) + { + size_t alc; + void *base; + + if (vec->size == 0) + alc = 32 * size; + else if (vec->size >= 4096) + alc = vec->size + 4096; + else + alc = 2 * vec->size; + + if (alc < vec->size + size) + alc = vec->size + size; + + base = realloc (vec->base, alc); + if (base == NULL) + { + error_callback (data, "realloc", errno); + return NULL; + } + + vec->base = base; + vec->alc = alc - vec->size; + } + + ret = (char *) vec->base + vec->size; + vec->size += size; + vec->alc -= size; + return ret; +} + +/* Finish the current allocation on VEC. */ + +void * +backtrace_vector_finish (struct backtrace_state *state, + struct backtrace_vector *vec, + backtrace_error_callback error_callback, + void *data) +{ + void *ret; + + /* With this allocator we call realloc in backtrace_vector_grow, + which means we can't easily reuse the memory here. So just + release it. */ + if (!backtrace_vector_release (state, vec, error_callback, data)) + return NULL; + ret = vec->base; + vec->base = NULL; + vec->size = 0; + vec->alc = 0; + return ret; +} + +/* Release any extra space allocated for VEC. */ + +int +backtrace_vector_release (struct backtrace_state *state ATTRIBUTE_UNUSED, + struct backtrace_vector *vec, + backtrace_error_callback error_callback, + void *data) +{ + vec->base = realloc (vec->base, vec->size); + if (vec->base == NULL) + { + error_callback (data, "realloc", errno); + return 0; + } + vec->alc = 0; + return 1; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/ansidecl.h b/backtrace-sys-0.1.16/src/libbacktrace/ansidecl.h new file mode 100644 index 000000000..08aeb1eeb --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/ansidecl.h @@ -0,0 +1,355 @@ +/* ANSI and traditional C compatability macros + Copyright (C) 1991-2015 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* ANSI and traditional C compatibility macros + + ANSI C is assumed if __STDC__ is #defined. + + Macro ANSI C definition Traditional C definition + ----- ---- - ---------- ----------- - ---------- + PTR `void *' `char *' + const not defined `' + volatile not defined `' + signed not defined `' + + For ease of writing code which uses GCC extensions but needs to be + portable to other compilers, we provide the GCC_VERSION macro that + simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various + wrappers around __attribute__. Also, __extension__ will be #defined + to nothing if it doesn't work. See below. */ + +#ifndef _ANSIDECL_H +#define _ANSIDECL_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Every source file includes this file, + so they will all get the switch for lint. */ +/* LINTLIBRARY */ + +/* Using MACRO(x,y) in cpp #if conditionals does not work with some + older preprocessors. Thus we can't define something like this: + +#define HAVE_GCC_VERSION(MAJOR, MINOR) \ + (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR))) + +and then test "#if HAVE_GCC_VERSION(2,7)". + +So instead we use the macro below and test it against specific values. */ + +/* This macro simplifies testing whether we are using gcc, and if it + is of a particular minimum version. (Both major & minor numbers are + significant.) This macro will evaluate to 0 if we are not using + gcc at all. */ +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +#endif /* GCC_VERSION */ + +#if defined (__STDC__) || defined(__cplusplus) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) +/* All known AIX compilers implement these things (but don't always + define __STDC__). The RISC/OS MIPS compiler defines these things + in SVR4 mode, but does not define __STDC__. */ +/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other + C++ compilers, does not define __STDC__, though it acts as if this + was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */ + +#define PTR void * + +#undef const +#undef volatile +#undef signed + +/* inline requires special treatment; it's in C99, and GCC >=2.7 supports + it too, but it's not in C89. */ +#undef inline +#if __STDC_VERSION__ >= 199901L || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__)) +/* it's a keyword */ +#else +# if GCC_VERSION >= 2007 +# define inline __inline__ /* __inline__ prevents -pedantic warnings */ +# else +# define inline /* nothing */ +# endif +#endif + +#else /* Not ANSI C. */ + +#define PTR char * + +/* some systems define these in header files for non-ansi mode */ +#undef const +#undef volatile +#undef signed +#undef inline +#define const +#define volatile +#define signed +#define inline + +#endif /* ANSI C. */ + +/* Define macros for some gcc attributes. This permits us to use the + macros freely, and know that they will come into play for the + version of gcc in which they are supported. */ + +#if (GCC_VERSION < 2007) +# define __attribute__(x) +#endif + +/* Attribute __malloc__ on functions was valid as of gcc 2.96. */ +#ifndef ATTRIBUTE_MALLOC +# if (GCC_VERSION >= 2096) +# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) +# else +# define ATTRIBUTE_MALLOC +# endif /* GNUC >= 2.96 */ +#endif /* ATTRIBUTE_MALLOC */ + +/* Attributes on labels were valid as of gcc 2.93 and g++ 4.5. For + g++ an attribute on a label must be followed by a semicolon. */ +#ifndef ATTRIBUTE_UNUSED_LABEL +# ifndef __cplusplus +# if GCC_VERSION >= 2093 +# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED +# else +# define ATTRIBUTE_UNUSED_LABEL +# endif +# else +# if GCC_VERSION >= 4005 +# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ; +# else +# define ATTRIBUTE_UNUSED_LABEL +# endif +# endif +#endif + +/* Similarly to ARG_UNUSED below. Prior to GCC 3.4, the C++ frontend + couldn't parse attributes placed after the identifier name, and now + the entire compiler is built with C++. */ +#ifndef ATTRIBUTE_UNUSED +#if GCC_VERSION >= 3004 +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#else +#define ATTRIBUTE_UNUSED +#endif +#endif /* ATTRIBUTE_UNUSED */ + +/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the + identifier name. */ +#if ! defined(__cplusplus) || (GCC_VERSION >= 3004) +# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED +#else /* !__cplusplus || GNUC >= 3.4 */ +# define ARG_UNUSED(NAME) NAME +#endif /* !__cplusplus || GNUC >= 3.4 */ + +#ifndef ATTRIBUTE_NORETURN +#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) +#endif /* ATTRIBUTE_NORETURN */ + +/* Attribute `nonnull' was valid as of gcc 3.3. */ +#ifndef ATTRIBUTE_NONNULL +# if (GCC_VERSION >= 3003) +# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m))) +# else +# define ATTRIBUTE_NONNULL(m) +# endif /* GNUC >= 3.3 */ +#endif /* ATTRIBUTE_NONNULL */ + +/* Attribute `returns_nonnull' was valid as of gcc 4.9. */ +#ifndef ATTRIBUTE_RETURNS_NONNULL +# if (GCC_VERSION >= 4009) +# define ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__)) +# else +# define ATTRIBUTE_RETURNS_NONNULL +# endif /* GNUC >= 4.9 */ +#endif /* ATTRIBUTE_RETURNS_NONNULL */ + +/* Attribute `pure' was valid as of gcc 3.0. */ +#ifndef ATTRIBUTE_PURE +# if (GCC_VERSION >= 3000) +# define ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define ATTRIBUTE_PURE +# endif /* GNUC >= 3.0 */ +#endif /* ATTRIBUTE_PURE */ + +/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL. + This was the case for the `printf' format attribute by itself + before GCC 3.3, but as of 3.3 we need to add the `nonnull' + attribute to retain this behavior. */ +#ifndef ATTRIBUTE_PRINTF +#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m) +#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2) +#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3) +#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4) +#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5) +#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6) +#endif /* ATTRIBUTE_PRINTF */ + +/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on + a function pointer. Format attributes were allowed on function + pointers as of gcc 3.1. */ +#ifndef ATTRIBUTE_FPTR_PRINTF +# if (GCC_VERSION >= 3001) +# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n) +# else +# define ATTRIBUTE_FPTR_PRINTF(m, n) +# endif /* GNUC >= 3.1 */ +# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2) +# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3) +# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4) +# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5) +# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6) +#endif /* ATTRIBUTE_FPTR_PRINTF */ + +/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A + NULL format specifier was allowed as of gcc 3.3. */ +#ifndef ATTRIBUTE_NULL_PRINTF +# if (GCC_VERSION >= 3003) +# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) +# else +# define ATTRIBUTE_NULL_PRINTF(m, n) +# endif /* GNUC >= 3.3 */ +# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2) +# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3) +# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4) +# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5) +# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6) +#endif /* ATTRIBUTE_NULL_PRINTF */ + +/* Attribute `sentinel' was valid as of gcc 3.5. */ +#ifndef ATTRIBUTE_SENTINEL +# if (GCC_VERSION >= 3005) +# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__)) +# else +# define ATTRIBUTE_SENTINEL +# endif /* GNUC >= 3.5 */ +#endif /* ATTRIBUTE_SENTINEL */ + + +#ifndef ATTRIBUTE_ALIGNED_ALIGNOF +# if (GCC_VERSION >= 3000) +# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m)))) +# else +# define ATTRIBUTE_ALIGNED_ALIGNOF(m) +# endif /* GNUC >= 3.0 */ +#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */ + +/* Useful for structures whose layout must much some binary specification + regardless of the alignment and padding qualities of the compiler. */ +#ifndef ATTRIBUTE_PACKED +# define ATTRIBUTE_PACKED __attribute__ ((packed)) +#endif + +/* Attribute `hot' and `cold' was valid as of gcc 4.3. */ +#ifndef ATTRIBUTE_COLD +# if (GCC_VERSION >= 4003) +# define ATTRIBUTE_COLD __attribute__ ((__cold__)) +# else +# define ATTRIBUTE_COLD +# endif /* GNUC >= 4.3 */ +#endif /* ATTRIBUTE_COLD */ +#ifndef ATTRIBUTE_HOT +# if (GCC_VERSION >= 4003) +# define ATTRIBUTE_HOT __attribute__ ((__hot__)) +# else +# define ATTRIBUTE_HOT +# endif /* GNUC >= 4.3 */ +#endif /* ATTRIBUTE_HOT */ + +/* Attribute 'no_sanitize_undefined' was valid as of gcc 4.9. */ +#ifndef ATTRIBUTE_NO_SANITIZE_UNDEFINED +# if (GCC_VERSION >= 4009) +# define ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__ ((no_sanitize_undefined)) +# else +# define ATTRIBUTE_NO_SANITIZE_UNDEFINED +# endif /* GNUC >= 4.9 */ +#endif /* ATTRIBUTE_NO_SANITIZE_UNDEFINED */ + +/* We use __extension__ in some places to suppress -pedantic warnings + about GCC extensions. This feature didn't work properly before + gcc 2.8. */ +#if GCC_VERSION < 2008 +#define __extension__ +#endif + +/* This is used to declare a const variable which should be visible + outside of the current compilation unit. Use it as + EXPORTED_CONST int i = 1; + This is because the semantics of const are different in C and C++. + "extern const" is permitted in C but it looks strange, and gcc + warns about it when -Wc++-compat is not used. */ +#ifdef __cplusplus +#define EXPORTED_CONST extern const +#else +#define EXPORTED_CONST const +#endif + +/* Be conservative and only use enum bitfields with C++ or GCC. + FIXME: provide a complete autoconf test for buggy enum bitfields. */ + +#ifdef __cplusplus +#define ENUM_BITFIELD(TYPE) enum TYPE +#elif (GCC_VERSION > 2000) +#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE +#else +#define ENUM_BITFIELD(TYPE) unsigned int +#endif + +/* C++11 adds the ability to add "override" after an implementation of a + virtual function in a subclass, to: + (A) document that this is an override of a virtual function + (B) allow the compiler to issue a warning if it isn't (e.g. a mismatch + of the type signature). + + Similarly, it allows us to add a "final" to indicate that no subclass + may subsequently override the vfunc. + + Provide OVERRIDE and FINAL as macros, allowing us to get these benefits + when compiling with C++11 support, but without requiring C++11. + + For gcc, use "-std=c++11" to enable C++11 support; gcc 6 onwards enables + this by default (actually GNU++14). */ + +#if __cplusplus >= 201103 +/* C++11 claims to be available: use it. final/override were only + implemented in 4.7, though. */ +# if GCC_VERSION < 4007 +# define OVERRIDE +# define FINAL +# else +# define OVERRIDE override +# define FINAL final +# endif +#elif GCC_VERSION >= 4007 +/* G++ 4.7 supports __final in C++98. */ +# define OVERRIDE +# define FINAL __final +#else +/* No C++11 support; leave the macros empty: */ +# define OVERRIDE +# define FINAL +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ansidecl.h */ diff --git a/backtrace-sys-0.1.16/src/libbacktrace/atomic.c b/backtrace-sys-0.1.16/src/libbacktrace/atomic.c new file mode 100644 index 000000000..4f31ff36f --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/atomic.c @@ -0,0 +1,113 @@ +/* atomic.c -- Support for atomic functions if not present. + Copyright (C) 2013-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include + +#include "backtrace.h" +#include "backtrace-supported.h" +#include "internal.h" + +/* This file holds implementations of the atomic functions that are + used if the host compiler has the sync functions but not the atomic + functions, as is true of versions of GCC before 4.7. */ + +#if !defined (HAVE_ATOMIC_FUNCTIONS) && defined (HAVE_SYNC_FUNCTIONS) + +/* Do an atomic load of a pointer. */ + +void * +backtrace_atomic_load_pointer (void *arg) +{ + void **pp; + void *p; + + pp = (void **) arg; + p = *pp; + while (!__sync_bool_compare_and_swap (pp, p, p)) + p = *pp; + return p; +} + +/* Do an atomic load of an int. */ + +int +backtrace_atomic_load_int (int *p) +{ + int i; + + i = *p; + while (!__sync_bool_compare_and_swap (p, i, i)) + i = *p; + return i; +} + +/* Do an atomic store of a pointer. */ + +void +backtrace_atomic_store_pointer (void *arg, void *p) +{ + void **pp; + void *old; + + pp = (void **) arg; + old = *pp; + while (!__sync_bool_compare_and_swap (pp, old, p)) + old = *pp; +} + +/* Do an atomic store of a size_t value. */ + +void +backtrace_atomic_store_size_t (size_t *p, size_t v) +{ + size_t old; + + old = *p; + while (!__sync_bool_compare_and_swap (p, old, v)) + old = *p; +} + +/* Do an atomic store of a int value. */ + +void +backtrace_atomic_store_int (int *p, int v) +{ + size_t old; + + old = *p; + while (!__sync_bool_compare_and_swap (p, old, v)) + old = *p; +} + +#endif diff --git a/backtrace-sys-0.1.16/src/libbacktrace/backtrace-supported.h.in b/backtrace-sys-0.1.16/src/libbacktrace/backtrace-supported.h.in new file mode 100644 index 000000000..c2d03d241 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/backtrace-supported.h.in @@ -0,0 +1,66 @@ +/* backtrace-supported.h.in -- Whether stack backtrace is supported. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +/* The file backtrace-supported.h.in is used by configure to generate + the file backtrace-supported.h. The file backtrace-supported.h may + be #include'd to see whether the backtrace library will be able to + get a backtrace and produce symbolic information. */ + + +/* BACKTRACE_SUPPORTED will be #define'd as 1 if the backtrace library + should work, 0 if it will not. Libraries may #include this to make + other arrangements. */ + +#define BACKTRACE_SUPPORTED @BACKTRACE_SUPPORTED@ + +/* BACKTRACE_USES_MALLOC will be #define'd as 1 if the backtrace + library will call malloc as it works, 0 if it will call mmap + instead. This may be used to determine whether it is safe to call + the backtrace functions from a signal handler. In general this + only applies to calls like backtrace and backtrace_pcinfo. It does + not apply to backtrace_simple, which never calls malloc. It does + not apply to backtrace_print, which always calls fprintf and + therefore malloc. */ + +#define BACKTRACE_USES_MALLOC @BACKTRACE_USES_MALLOC@ + +/* BACKTRACE_SUPPORTS_THREADS will be #define'd as 1 if the backtrace + library is configured with threading support, 0 if not. If this is + 0, the threaded parameter to backtrace_create_state must be passed + as 0. */ + +#define BACKTRACE_SUPPORTS_THREADS @BACKTRACE_SUPPORTS_THREADS@ + +/* BACKTRACE_SUPPORTS_DATA will be #defined'd as 1 if the backtrace_syminfo + will work for variables. It will always work for functions. */ + +#define BACKTRACE_SUPPORTS_DATA @BACKTRACE_SUPPORTS_DATA@ diff --git a/backtrace-sys-0.1.16/src/libbacktrace/backtrace.c b/backtrace-sys-0.1.16/src/libbacktrace/backtrace.c new file mode 100644 index 000000000..7372a27f1 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/backtrace.c @@ -0,0 +1,129 @@ +/* backtrace.c -- Entry point for stack backtrace library. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include + +#include "unwind.h" +#include "backtrace.h" +#include "internal.h" + +/* The main backtrace_full routine. */ + +/* Data passed through _Unwind_Backtrace. */ + +struct backtrace_data +{ + /* Number of frames to skip. */ + int skip; + /* Library state. */ + struct backtrace_state *state; + /* Callback routine. */ + backtrace_full_callback callback; + /* Error callback routine. */ + backtrace_error_callback error_callback; + /* Data to pass to callback routines. */ + void *data; + /* Value to return from backtrace_full. */ + int ret; + /* Whether there is any memory available. */ + int can_alloc; +}; + +/* Unwind library callback routine. This is passed to + _Unwind_Backtrace. */ + +static _Unwind_Reason_Code +unwind (struct _Unwind_Context *context, void *vdata) +{ + struct backtrace_data *bdata = (struct backtrace_data *) vdata; + uintptr_t pc; + int ip_before_insn = 0; + +#ifdef HAVE_GETIPINFO + pc = _Unwind_GetIPInfo (context, &ip_before_insn); +#else + pc = _Unwind_GetIP (context); +#endif + + if (bdata->skip > 0) + { + --bdata->skip; + return _URC_NO_REASON; + } + + if (!ip_before_insn) + --pc; + + if (!bdata->can_alloc) + bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL); + else + bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback, + bdata->error_callback, bdata->data); + if (bdata->ret != 0) + return _URC_END_OF_STACK; + + return _URC_NO_REASON; +} + +/* Get a stack backtrace. */ + +int +backtrace_full (struct backtrace_state *state, int skip, + backtrace_full_callback callback, + backtrace_error_callback error_callback, void *data) +{ + struct backtrace_data bdata; + void *p; + + bdata.skip = skip + 1; + bdata.state = state; + bdata.callback = callback; + bdata.error_callback = error_callback; + bdata.data = data; + bdata.ret = 0; + + /* If we can't allocate any memory at all, don't try to produce + file/line information. */ + p = backtrace_alloc (state, 4096, NULL, NULL); + if (p == NULL) + bdata.can_alloc = 0; + else + { + backtrace_free (state, p, 4096, NULL, NULL); + bdata.can_alloc = 1; + } + + _Unwind_Backtrace (unwind, &bdata); + return bdata.ret; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/backtrace.h b/backtrace-sys-0.1.16/src/libbacktrace/backtrace.h new file mode 100644 index 000000000..0e6e29f39 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/backtrace.h @@ -0,0 +1,199 @@ +/* backtrace.h -- Public header file for stack backtrace library. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#ifndef BACKTRACE_H +#define BACKTRACE_H + +#include +#include + +/* We want to get a definition for uintptr_t, but we still care about + systems that don't have . */ +#if defined(__GLIBC__) && __GLIBC__ >= 2 + +#include + +#elif defined(HAVE_STDINT_H) + +#include + +#else + +/* Systems that don't have must provide gstdint.h, e.g., + from GCC_HEADER_STDINT in configure.ac. */ +#include "gstdint.h" + +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* The backtrace state. This struct is intentionally not defined in + the public interface. */ + +struct backtrace_state; + +/* The type of the error callback argument to backtrace functions. + This function, if not NULL, will be called for certain error cases. + The DATA argument is passed to the function that calls this one. + The MSG argument is an error message. The ERRNUM argument, if + greater than 0, holds an errno value. The MSG buffer may become + invalid after this function returns. + + As a special case, the ERRNUM argument will be passed as -1 if no + debug info can be found for the executable, but the function + requires debug info (e.g., backtrace_full, backtrace_pcinfo). The + MSG in this case will be something along the lines of "no debug + info". Similarly, ERRNUM will be passed as -1 if there is no + symbol table, but the function requires a symbol table (e.g., + backtrace_syminfo). This may be used as a signal that some other + approach should be tried. */ + +typedef void (*backtrace_error_callback) (void *data, const char *msg, + int errnum); + +/* Create state information for the backtrace routines. This must be + called before any of the other routines, and its return value must + be passed to all of the other routines. FILENAME is the path name + of the executable file; if it is NULL the library will try + system-specific path names. If not NULL, FILENAME must point to a + permanent buffer. If THREADED is non-zero the state may be + accessed by multiple threads simultaneously, and the library will + use appropriate atomic operations. If THREADED is zero the state + may only be accessed by one thread at a time. This returns a state + pointer on success, NULL on error. If an error occurs, this will + call the ERROR_CALLBACK routine. */ + +extern struct backtrace_state *backtrace_create_state ( + const char *filename, int threaded, + backtrace_error_callback error_callback, void *data); + +/* The type of the callback argument to the backtrace_full function. + DATA is the argument passed to backtrace_full. PC is the program + counter. FILENAME is the name of the file containing PC, or NULL + if not available. LINENO is the line number in FILENAME containing + PC, or 0 if not available. FUNCTION is the name of the function + containing PC, or NULL if not available. This should return 0 to + continuing tracing. The FILENAME and FUNCTION buffers may become + invalid after this function returns. */ + +typedef int (*backtrace_full_callback) (void *data, uintptr_t pc, + const char *filename, int lineno, + const char *function); + +/* Get a full stack backtrace. SKIP is the number of frames to skip; + passing 0 will start the trace with the function calling + backtrace_full. DATA is passed to the callback routine. If any + call to CALLBACK returns a non-zero value, the stack backtrace + stops, and backtrace returns that value; this may be used to limit + the number of stack frames desired. If all calls to CALLBACK + return 0, backtrace returns 0. The backtrace_full function will + make at least one call to either CALLBACK or ERROR_CALLBACK. This + function requires debug info for the executable. */ + +extern int backtrace_full (struct backtrace_state *state, int skip, + backtrace_full_callback callback, + backtrace_error_callback error_callback, + void *data); + +/* The type of the callback argument to the backtrace_simple function. + DATA is the argument passed to simple_backtrace. PC is the program + counter. This should return 0 to continue tracing. */ + +typedef int (*backtrace_simple_callback) (void *data, uintptr_t pc); + +/* Get a simple backtrace. SKIP is the number of frames to skip, as + in backtrace. DATA is passed to the callback routine. If any call + to CALLBACK returns a non-zero value, the stack backtrace stops, + and backtrace_simple returns that value. Otherwise + backtrace_simple returns 0. The backtrace_simple function will + make at least one call to either CALLBACK or ERROR_CALLBACK. This + function does not require any debug info for the executable. */ + +extern int backtrace_simple (struct backtrace_state *state, int skip, + backtrace_simple_callback callback, + backtrace_error_callback error_callback, + void *data); + +/* Print the current backtrace in a user readable format to a FILE. + SKIP is the number of frames to skip, as in backtrace_full. Any + error messages are printed to stderr. This function requires debug + info for the executable. */ + +extern void backtrace_print (struct backtrace_state *state, int skip, FILE *); + +/* Given PC, a program counter in the current program, call the + callback function with filename, line number, and function name + information. This will normally call the callback function exactly + once. However, if the PC happens to describe an inlined call, and + the debugging information contains the necessary information, then + this may call the callback function multiple times. This will make + at least one call to either CALLBACK or ERROR_CALLBACK. This + returns the first non-zero value returned by CALLBACK, or 0. */ + +extern int backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc, + backtrace_full_callback callback, + backtrace_error_callback error_callback, + void *data); + +/* The type of the callback argument to backtrace_syminfo. DATA and + PC are the arguments passed to backtrace_syminfo. SYMNAME is the + name of the symbol for the corresponding code. SYMVAL is the + value and SYMSIZE is the size of the symbol. SYMNAME will be NULL + if no error occurred but the symbol could not be found. */ + +typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc, + const char *symname, + uintptr_t symval, + uintptr_t symsize); + +/* Given ADDR, an address or program counter in the current program, + call the callback information with the symbol name and value + describing the function or variable in which ADDR may be found. + This will call either CALLBACK or ERROR_CALLBACK exactly once. + This returns 1 on success, 0 on failure. This function requires + the symbol table but does not require the debug info. Note that if + the symbol table is present but ADDR could not be found in the + table, CALLBACK will be called with a NULL SYMNAME argument. + Returns 1 on success, 0 on error. */ + +extern int backtrace_syminfo (struct backtrace_state *state, uintptr_t addr, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback, + void *data); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif + +#endif diff --git a/backtrace-sys-0.1.16/src/libbacktrace/btest.c b/backtrace-sys-0.1.16/src/libbacktrace/btest.c new file mode 100644 index 000000000..8c69b1b87 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/btest.c @@ -0,0 +1,721 @@ +/* btest.c -- Test for libbacktrace library + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +/* This program tests the externally visible interfaces of the + libbacktrace library. */ + +#include +#include +#include +#include + +#include "filenames.h" + +#include "backtrace.h" +#include "backtrace-supported.h" + +/* Portable attribute syntax. Actually some of these tests probably + won't work if the attributes are not recognized. */ + +#ifndef GCC_VERSION +# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +#endif + +#if (GCC_VERSION < 2007) +# define __attribute__(x) +#endif + +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif + +/* Used to collect backtrace info. */ + +struct info +{ + char *filename; + int lineno; + char *function; +}; + +/* Passed to backtrace callback function. */ + +struct bdata +{ + struct info *all; + size_t index; + size_t max; + int failed; +}; + +/* Passed to backtrace_simple callback function. */ + +struct sdata +{ + uintptr_t *addrs; + size_t index; + size_t max; + int failed; +}; + +/* Passed to backtrace_syminfo callback function. */ + +struct symdata +{ + const char *name; + uintptr_t val, size; + int failed; +}; + +/* The backtrace state. */ + +static void *state; + +/* The number of failures. */ + +static int failures; + +/* Return the base name in a path. */ + +static const char * +base (const char *p) +{ + const char *last; + const char *s; + + last = NULL; + for (s = p; *s != '\0'; ++s) + { + if (IS_DIR_SEPARATOR (*s)) + last = s + 1; + } + return last != NULL ? last : p; +} + +/* Check an entry in a struct info array. */ + +static void +check (const char *name, int index, const struct info *all, int want_lineno, + const char *want_function, int *failed) +{ + if (*failed) + return; + if (all[index].filename == NULL || all[index].function == NULL) + { + fprintf (stderr, "%s: [%d]: missing file name or function name\n", + name, index); + *failed = 1; + return; + } + if (strcmp (base (all[index].filename), "btest.c") != 0) + { + fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index, + all[index].filename); + *failed = 1; + } + if (all[index].lineno != want_lineno) + { + fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index, + all[index].lineno, want_lineno); + *failed = 1; + } + if (strcmp (all[index].function, want_function) != 0) + { + fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index, + all[index].function, want_function); + *failed = 1; + } +} + +/* The backtrace callback function. */ + +static int +callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED, + const char *filename, int lineno, const char *function) +{ + struct bdata *data = (struct bdata *) vdata; + struct info *p; + + if (data->index >= data->max) + { + fprintf (stderr, "callback_one: callback called too many times\n"); + data->failed = 1; + return 1; + } + + p = &data->all[data->index]; + if (filename == NULL) + p->filename = NULL; + else + { + p->filename = strdup (filename); + assert (p->filename != NULL); + } + p->lineno = lineno; + if (function == NULL) + p->function = NULL; + else + { + p->function = strdup (function); + assert (p->function != NULL); + } + ++data->index; + + return 0; +} + +/* An error callback passed to backtrace. */ + +static void +error_callback_one (void *vdata, const char *msg, int errnum) +{ + struct bdata *data = (struct bdata *) vdata; + + fprintf (stderr, "%s", msg); + if (errnum > 0) + fprintf (stderr, ": %s", strerror (errnum)); + fprintf (stderr, "\n"); + data->failed = 1; +} + +/* The backtrace_simple callback function. */ + +static int +callback_two (void *vdata, uintptr_t pc) +{ + struct sdata *data = (struct sdata *) vdata; + + if (data->index >= data->max) + { + fprintf (stderr, "callback_two: callback called too many times\n"); + data->failed = 1; + return 1; + } + + data->addrs[data->index] = pc; + ++data->index; + + return 0; +} + +/* An error callback passed to backtrace_simple. */ + +static void +error_callback_two (void *vdata, const char *msg, int errnum) +{ + struct sdata *data = (struct sdata *) vdata; + + fprintf (stderr, "%s", msg); + if (errnum > 0) + fprintf (stderr, ": %s", strerror (errnum)); + fprintf (stderr, "\n"); + data->failed = 1; +} + +/* The backtrace_syminfo callback function. */ + +static void +callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED, + const char *symname, uintptr_t symval, + uintptr_t symsize) +{ + struct symdata *data = (struct symdata *) vdata; + + if (symname == NULL) + data->name = NULL; + else + { + data->name = strdup (symname); + assert (data->name != NULL); + } + data->val = symval; + data->size = symsize; +} + +/* The backtrace_syminfo error callback function. */ + +static void +error_callback_three (void *vdata, const char *msg, int errnum) +{ + struct symdata *data = (struct symdata *) vdata; + + fprintf (stderr, "%s", msg); + if (errnum > 0) + fprintf (stderr, ": %s", strerror (errnum)); + fprintf (stderr, "\n"); + data->failed = 1; +} + +/* Test the backtrace function with non-inlined functions. */ + +static int test1 (void) __attribute__ ((noinline, unused)); +static int f2 (int) __attribute__ ((noinline)); +static int f3 (int, int) __attribute__ ((noinline)); + +static int +test1 (void) +{ + /* Returning a value here and elsewhere avoids a tailcall which + would mess up the backtrace. */ + return f2 (__LINE__) + 1; +} + +static int +f2 (int f1line) +{ + return f3 (f1line, __LINE__) + 2; +} + +static int +f3 (int f1line, int f2line) +{ + struct info all[20]; + struct bdata data; + int f3line; + int i; + + data.all = &all[0]; + data.index = 0; + data.max = 20; + data.failed = 0; + + f3line = __LINE__ + 1; + i = backtrace_full (state, 0, callback_one, error_callback_one, &data); + + if (i != 0) + { + fprintf (stderr, "test1: unexpected return value %d\n", i); + data.failed = 1; + } + + if (data.index < 3) + { + fprintf (stderr, + "test1: not enough frames; got %zu, expected at least 3\n", + data.index); + data.failed = 1; + } + + check ("test1", 0, all, f3line, "f3", &data.failed); + check ("test1", 1, all, f2line, "f2", &data.failed); + check ("test1", 2, all, f1line, "test1", &data.failed); + + printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS"); + + if (data.failed) + ++failures; + + return failures; +} + +/* Test the backtrace function with inlined functions. */ + +static inline int test2 (void) __attribute__ ((always_inline, unused)); +static inline int f12 (int) __attribute__ ((always_inline)); +static inline int f13 (int, int) __attribute__ ((always_inline)); + +static inline int +test2 (void) +{ + return f12 (__LINE__) + 1; +} + +static inline int +f12 (int f1line) +{ + return f13 (f1line, __LINE__) + 2; +} + +static inline int +f13 (int f1line, int f2line) +{ + struct info all[20]; + struct bdata data; + int f3line; + int i; + + data.all = &all[0]; + data.index = 0; + data.max = 20; + data.failed = 0; + + f3line = __LINE__ + 1; + i = backtrace_full (state, 0, callback_one, error_callback_one, &data); + + if (i != 0) + { + fprintf (stderr, "test2: unexpected return value %d\n", i); + data.failed = 1; + } + + check ("test2", 0, all, f3line, "f13", &data.failed); + check ("test2", 1, all, f2line, "f12", &data.failed); + check ("test2", 2, all, f1line, "test2", &data.failed); + + printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS"); + + if (data.failed) + ++failures; + + return failures; +} + +/* Test the backtrace_simple function with non-inlined functions. */ + +static int test3 (void) __attribute__ ((noinline, unused)); +static int f22 (int) __attribute__ ((noinline)); +static int f23 (int, int) __attribute__ ((noinline)); + +static int +test3 (void) +{ + return f22 (__LINE__) + 1; +} + +static int +f22 (int f1line) +{ + return f23 (f1line, __LINE__) + 2; +} + +static int +f23 (int f1line, int f2line) +{ + uintptr_t addrs[20]; + struct sdata data; + int f3line; + int i; + + data.addrs = &addrs[0]; + data.index = 0; + data.max = 20; + data.failed = 0; + + f3line = __LINE__ + 1; + i = backtrace_simple (state, 0, callback_two, error_callback_two, &data); + + if (i != 0) + { + fprintf (stderr, "test3: unexpected return value %d\n", i); + data.failed = 1; + } + + if (!data.failed) + { + struct info all[20]; + struct bdata bdata; + int j; + + bdata.all = &all[0]; + bdata.index = 0; + bdata.max = 20; + bdata.failed = 0; + + for (j = 0; j < 3; ++j) + { + i = backtrace_pcinfo (state, addrs[j], callback_one, + error_callback_one, &bdata); + if (i != 0) + { + fprintf (stderr, + ("test3: unexpected return value " + "from backtrace_pcinfo %d\n"), + i); + bdata.failed = 1; + } + if (!bdata.failed && bdata.index != (size_t) (j + 1)) + { + fprintf (stderr, + ("wrong number of calls from backtrace_pcinfo " + "got %u expected %d\n"), + (unsigned int) bdata.index, j + 1); + bdata.failed = 1; + } + } + + check ("test3", 0, all, f3line, "f23", &bdata.failed); + check ("test3", 1, all, f2line, "f22", &bdata.failed); + check ("test3", 2, all, f1line, "test3", &bdata.failed); + + if (bdata.failed) + data.failed = 1; + + for (j = 0; j < 3; ++j) + { + struct symdata symdata; + + symdata.name = NULL; + symdata.val = 0; + symdata.size = 0; + symdata.failed = 0; + + i = backtrace_syminfo (state, addrs[j], callback_three, + error_callback_three, &symdata); + if (i == 0) + { + fprintf (stderr, + ("test3: [%d]: unexpected return value " + "from backtrace_syminfo %d\n"), + j, i); + symdata.failed = 1; + } + + if (!symdata.failed) + { + const char *expected; + + switch (j) + { + case 0: + expected = "f23"; + break; + case 1: + expected = "f22"; + break; + case 2: + expected = "test3"; + break; + default: + assert (0); + } + + if (symdata.name == NULL) + { + fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j); + symdata.failed = 1; + } + /* Use strncmp, not strcmp, because GCC might create a + clone. */ + else if (strncmp (symdata.name, expected, strlen (expected)) + != 0) + { + fprintf (stderr, + ("test3: [%d]: unexpected syminfo name " + "got %s expected %s\n"), + j, symdata.name, expected); + symdata.failed = 1; + } + } + + if (symdata.failed) + data.failed = 1; + } + } + + printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS"); + + if (data.failed) + ++failures; + + return failures; +} + +/* Test the backtrace_simple function with inlined functions. */ + +static inline int test4 (void) __attribute__ ((always_inline, unused)); +static inline int f32 (int) __attribute__ ((always_inline)); +static inline int f33 (int, int) __attribute__ ((always_inline)); + +static inline int +test4 (void) +{ + return f32 (__LINE__) + 1; +} + +static inline int +f32 (int f1line) +{ + return f33 (f1line, __LINE__) + 2; +} + +static inline int +f33 (int f1line, int f2line) +{ + uintptr_t addrs[20]; + struct sdata data; + int f3line; + int i; + + data.addrs = &addrs[0]; + data.index = 0; + data.max = 20; + data.failed = 0; + + f3line = __LINE__ + 1; + i = backtrace_simple (state, 0, callback_two, error_callback_two, &data); + + if (i != 0) + { + fprintf (stderr, "test3: unexpected return value %d\n", i); + data.failed = 1; + } + + if (!data.failed) + { + struct info all[20]; + struct bdata bdata; + + bdata.all = &all[0]; + bdata.index = 0; + bdata.max = 20; + bdata.failed = 0; + + i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one, + &bdata); + if (i != 0) + { + fprintf (stderr, + ("test4: unexpected return value " + "from backtrace_pcinfo %d\n"), + i); + bdata.failed = 1; + } + + check ("test4", 0, all, f3line, "f33", &bdata.failed); + check ("test4", 1, all, f2line, "f32", &bdata.failed); + check ("test4", 2, all, f1line, "test4", &bdata.failed); + + if (bdata.failed) + data.failed = 1; + } + + printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS"); + + if (data.failed) + ++failures; + + return failures; +} + +#if BACKTRACE_SUPPORTS_DATA + +int global = 1; + +static int +test5 (void) +{ + struct symdata symdata; + int i; + uintptr_t addr = (uintptr_t) &global; + + if (sizeof (global) > 1) + addr += 1; + + symdata.name = NULL; + symdata.val = 0; + symdata.size = 0; + symdata.failed = 0; + + i = backtrace_syminfo (state, addr, callback_three, + error_callback_three, &symdata); + if (i == 0) + { + fprintf (stderr, + "test5: unexpected return value from backtrace_syminfo %d\n", + i); + symdata.failed = 1; + } + + if (!symdata.failed) + { + if (symdata.name == NULL) + { + fprintf (stderr, "test5: NULL syminfo name\n"); + symdata.failed = 1; + } + else if (strcmp (symdata.name, "global") != 0) + { + fprintf (stderr, + "test5: unexpected syminfo name got %s expected %s\n", + symdata.name, "global"); + symdata.failed = 1; + } + else if (symdata.val != (uintptr_t) &global) + { + fprintf (stderr, + "test5: unexpected syminfo value got %lx expected %lx\n", + (unsigned long) symdata.val, + (unsigned long) (uintptr_t) &global); + symdata.failed = 1; + } + else if (symdata.size != sizeof (global)) + { + fprintf (stderr, + "test5: unexpected syminfo size got %lx expected %lx\n", + (unsigned long) symdata.size, + (unsigned long) sizeof (global)); + symdata.failed = 1; + } + } + + printf ("%s: backtrace_syminfo variable\n", + symdata.failed ? "FAIL" : "PASS"); + + if (symdata.failed) + ++failures; + + return failures; +} + +#endif /* BACKTRACE_SUPPORTS_DATA */ + +static void +error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg, + int errnum) +{ + fprintf (stderr, "%s", msg); + if (errnum > 0) + fprintf (stderr, ": %s", strerror (errnum)); + fprintf (stderr, "\n"); + exit (EXIT_FAILURE); +} + +/* Run all the tests. */ + +int +main (int argc ATTRIBUTE_UNUSED, char **argv) +{ + state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS, + error_callback_create, NULL); + +#if BACKTRACE_SUPPORTED + test1 (); + test2 (); + test3 (); + test4 (); +#if BACKTRACE_SUPPORTS_DATA + test5 (); +#endif +#endif + + exit (failures ? EXIT_FAILURE : EXIT_SUCCESS); +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/config.guess b/backtrace-sys-0.1.16/src/libbacktrace/config.guess new file mode 100755 index 000000000..2e9ad7fe8 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/config.guess @@ -0,0 +1,1462 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2016 Free Software Foundation, Inc. + +timestamp='2016-10-02' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2016 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = hppa2.0w ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + mips64el:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = 386; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +cat >&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/backtrace-sys-0.1.16/src/libbacktrace/config.h.in b/backtrace-sys-0.1.16/src/libbacktrace/config.h.in new file mode 100644 index 000000000..87cb80598 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/config.h.in @@ -0,0 +1,134 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* ELF size: 32 or 64 */ +#undef BACKTRACE_ELF_SIZE + +/* Define to 1 if you have the __atomic functions */ +#undef HAVE_ATOMIC_FUNCTIONS + +/* Define to 1 if you have the declaration of `strnlen', and to 0 if you + don't. */ +#undef HAVE_DECL_STRNLEN + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define if dl_iterate_phdr is available. */ +#undef HAVE_DL_ITERATE_PHDR + +/* Define to 1 if you have the fcntl function */ +#undef HAVE_FCNTL + +/* Define if getexecname is available. */ +#undef HAVE_GETEXECNAME + +/* Define if _Unwind_GetIPInfo is available. */ +#undef HAVE_GETIPINFO + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINK_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the __sync functions */ +#undef HAVE_SYNC_FUNCTIONS + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MMAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of `char', as computed by sizeof. */ +#undef SIZEOF_CHAR + +/* The size of `int', as computed by sizeof. */ +#undef SIZEOF_INT + +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `short', as computed by sizeof. */ +#undef SIZEOF_SHORT + +/* The size of `void *', as computed by sizeof. */ +#undef SIZEOF_VOID_P + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#undef _POSIX_SOURCE diff --git a/backtrace-sys-0.1.16/src/libbacktrace/config.sub b/backtrace-sys-0.1.16/src/libbacktrace/config.sub new file mode 100755 index 000000000..3478c1fd0 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/config.sub @@ -0,0 +1,1825 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2016 Free Software Foundation, Inc. + +timestamp='2016-11-19' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2016 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix* | -fuchsia*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -ios) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/backtrace-sys-0.1.16/src/libbacktrace/configure b/backtrace-sys-0.1.16/src/libbacktrace/configure new file mode 100755 index 000000000..5e743c2b4 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/configure @@ -0,0 +1,15189 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.64 for package-unused version-unused. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software +# Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='package-unused' +PACKAGE_TARNAME='libbacktrace' +PACKAGE_VERSION='version-unused' +PACKAGE_STRING='package-unused version-unused' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="backtrace.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +NATIVE_FALSE +NATIVE_TRUE +BACKTRACE_USES_MALLOC +ALLOC_FILE +VIEW_FILE +BACKTRACE_SUPPORTS_DATA +BACKTRACE_SUPPORTED +FORMAT_FILE +BACKTRACE_SUPPORTS_THREADS +PIC_FLAG +WARN_FLAGS +EXTRA_FLAGS +BACKTRACE_FILE +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +AR +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +SED +LIBTOOL +RANLIB +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +libtool_VERSION +EGREP +GREP +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +multi_basedir +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_multilib +enable_maintainer_mode +with_target_subdir +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +enable_libtool_lock +with_system_libunwind +enable_host_shared +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information." + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures package-unused version-unused to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/libbacktrace] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of package-unused version-unused:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-multilib build many library versions (default) + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + --enable-host-shared build host code as shared libraries + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-target-subdir=SUBDIR Configuring in a subdirectory for target + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-system-libunwind use installed libunwind + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +package-unused configure version-unused +generated by GNU Autoconf 2.64 + +Copyright (C) 2009 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_func + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_type + +# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES +# -------------------------------------------- +# Tries to find the compile-time value of EXPR in a program that includes +# INCLUDES, setting VAR accordingly. Returns whether the value could be +# computed +ac_fn_c_compute_int () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=0 ac_mid=0 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid; break +else + as_fn_arith $ac_mid + 1 && ac_lo=$as_val + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=-1 ac_mid=-1 + while :; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_lo=$ac_mid; break +else + as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + ac_lo= ac_hi= +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +static int test_array [1 - 2 * !(($2) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_hi=$ac_mid +else + as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in #(( +?*) eval "$3=\$ac_lo"; ac_retval=0 ;; +'') ac_retval=1 ;; +esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +static long int longval () { return $2; } +static unsigned long int ulongval () { return $2; } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (($2) < 0) + { + long int i = longval (); + if (i != ($2)) + return 1; + fprintf (f, "%ld", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ($2)) + return 1; + fprintf (f, "%lu", i); + } + /* Do not output a trailing newline, as this causes \r\n confusion + on some platforms. */ + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + echo >>conftest.val; read $3 &5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_decl +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by package-unused $as_me version-unused, which was +generated by GNU Autoconf 2.64. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + ac_site_file1=$CONFIG_SITE +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + +ac_config_headers="$ac_config_headers config.h" + + +if test -n "${with_target_subdir}"; then + # Default to --enable-multilib +# Check whether --enable-multilib was given. +if test "${enable_multilib+set}" = set; then : + enableval=$enable_multilib; case "$enableval" in + yes) multilib=yes ;; + no) multilib=no ;; + *) as_fn_error "bad value $enableval for multilib option" "$LINENO" 5 ;; + esac +else + multilib=yes +fi + + +# We may get other options which we leave undocumented: +# --with-target-subdir, --with-multisrctop, --with-multisubdir +# See config-ml.in if you want the gory details. + +if test "$srcdir" = "."; then + if test "$with_target_subdir" != "."; then + multi_basedir="$srcdir/$with_multisrctop../.." + else + multi_basedir="$srcdir/$with_multisrctop.." + fi +else + multi_basedir="$srcdir/.." +fi + + +# Even if the default multilib is not a cross compilation, +# it may be that some of the other multilibs are. +if test $cross_compiling = no && test $multilib = yes \ + && test "x${with_multisubdir}" != x ; then + cross_compiling=maybe +fi + +ac_config_commands="$ac_config_commands default-1" + +fi + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + for ac_t in install-sh install.sh shtool; do + if test -f "$ac_dir/$ac_t"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/$ac_t -c" + break 2 + fi + done +done +if test -z "$ac_aux_dir"; then + as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if test "${ac_cv_target+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +target_alias=${target_alias-$host_alias} + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "no acceptable C compiler found in \$PATH +See \`config.log' for more details." "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + rm -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +if test -z "$ac_file"; then : + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "C compiler cannot create executables +See \`config.log' for more details." "$LINENO" 5; }; } +fi +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of object files: cannot compile +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" +if test "x$ac_cv_header_minix_config_h" = x""yes; then : + MINIX=yes +else + MINIX= +fi + + + if test "$MINIX" = yes; then + +$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h + + +$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h + + +$as_echo "#define _MINIX 1" >>confdefs.h + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 +$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } +if test "${ac_cv_safe_to_define___extensions__+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# define __EXTENSIONS__ 1 + $ac_includes_default +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_safe_to_define___extensions__=yes +else + ac_cv_safe_to_define___extensions__=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 +$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } + test $ac_cv_safe_to_define___extensions__ = yes && + $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h + + $as_echo "#define _ALL_SOURCE 1" >>confdefs.h + + $as_echo "#define _GNU_SOURCE 1" >>confdefs.h + + $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + + $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h + + + +libtool_VERSION=1:0:0 + + +# 1.11.1: Require that version of automake. +# foreign: Don't require README, INSTALL, NEWS, etc. +# no-define: Don't define PACKAGE and VERSION. +# no-dependencies: Don't generate automatic dependencies. +# (because it breaks when using bootstrap-lean, since some of the +# headers are gone at "make install" time). +# -Wall: Issue all automake warnings. +# -Wno-portability: Don't warn about constructs supported by GNU make. +# (because GCC requires GNU make anyhow). +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + test -d ./--version && rmdir ./--version + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='libbacktrace' + VERSION='version-unused' + + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + +am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + + +# Check whether --with-target-subdir was given. +if test "${with_target_subdir+set}" = set; then : + withval=$with_target_subdir; +fi + + +# We must force CC to /not/ be precious variables; otherwise +# the wrong, non-multilib-adjusted value will be used in multilibs. +# As a side effect, we have to subst CFLAGS ourselves. + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "no acceptable C compiler found in \$PATH +See \`config.log' for more details." "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + rm -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +case "$AWK" in +"") as_fn_error "can't build without awk" "$LINENO" 5 ;; +esac + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.2.7a' +macro_revision='1.3134' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`print -r -- -n 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case "$ECHO" in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if test "${ac_cv_path_SED+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if test "${ac_cv_path_FGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if test "${lt_cv_path_LD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if test "${lt_cv_prog_gnu_ld+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if test "${lt_cv_path_NM+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DUMPBIN+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if test "${lt_cv_nm_interface+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if test "${lt_cv_sys_max_cmd_len+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if test "${lt_cv_ld_reload_flag+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if test "${lt_cv_deplibs_check_method+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. +set dummy ${ac_tool_prefix}ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="${ac_tool_prefix}ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_AR"; then + ac_ct_AR=$AR + # Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="ar" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +else + AR="$ac_cv_prog_AR" +fi + +test -z "$AR" && AR=ar +test -z "$AR_FLAGS" && AR_FLAGS=cru + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_save_LIBS="$LIBS" + lt_save_CFLAGS="$CFLAGS" + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS="$lt_save_LIBS" + CFLAGS="$lt_save_CFLAGS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + + + + + + + + + + + + + + + + + + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + case `/usr/bin/file conftest.o` in + *x86-64*) + LD="${LD-ld} -m elf32_x86_64" + ;; + *) + LD="${LD-ld} -m elf_i386" + ;; + esac + ;; + powerpc64le-*linux*) + LD="${LD-ld} -m elf32lppclinux" + ;; + powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + powerpcle-*linux*) + LD="${LD-ld} -m elf64lppc" + ;; + powerpc-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if test "${lt_cv_cc_needs_belf+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +sparc*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) LD="${LD-ld} -m elf64_sparc" ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_DSYMUTIL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_NMEDIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_LIPO+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_OTOOL64+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if test "${lt_cv_apple_cc_single_mod+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if test "${lt_cv_ld_exported_symbols_list+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if test "${lt_cv_ld_force_load+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012][,.]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + + +# Set options + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; pic_mode="$withval" +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if test "${lt_cv_objdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + lt_prog_compiler_pic='-fPIC' + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + lt_prog_compiler_pic='-Xcompiler -fPIC' + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ F* | *Sun*Fortran*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 +$as_echo "$lt_prog_compiler_pic" >&6; } + + + + + + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if test "${lt_cv_prog_compiler_pic_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if test "${lt_cv_prog_compiler_static_works+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if test "${lt_cv_prog_compiler_c_o+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='${wl}--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec= + hardcode_libdir_flag_spec_ld='-rpath $libdir' + archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\(.*\)$/\1/ + p + } + }' +aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +# Check for a 64-bit object if we didn't find anything. +if test -z "$aix_libpath"; then + aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + fix_srcfile_path='`cygpath -w "$srcfile"`' + enable_shared_with_static_runtimes=yes + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_flag_spec_ld='+b $libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if test "${lt_cv_prog_compiler__b+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test x"$lt_cv_prog_compiler__b" = xyes; then + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo(void) {} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if test "${lt_cv_archive_cmds_need_lc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([A-Za-z]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$host_os in + yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + ;; + + *) + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + ;; + esac + dynamic_linker='Win32 ld.exe' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if test "${lt_cv_shlibpath_overrides_runpath+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = x""yes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if test "${ac_cv_lib_dld_shl_load+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if test "${ac_cv_lib_dl_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if test "${ac_cv_lib_svld_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = x""yes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if test "${ac_cv_lib_dld_dld_link+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = x""yes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 11134 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +void fnord () __attribute__((visibility("default"))); +#endif + +void fnord () { int i=42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if test "${lt_cv_dlopen_self_static+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line 11240 "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +void fnord () __attribute__((visibility("default"))); +#endif + +void fnord () { int i=42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + + +backtrace_supported=yes + +if test -n "${with_target_subdir}"; then + # We are compiling a GCC library. We can assume that the unwind + # library exists. + BACKTRACE_FILE="backtrace.lo simple.lo" +else + ac_fn_c_check_header_mongrel "$LINENO" "unwind.h" "ac_cv_header_unwind_h" "$ac_includes_default" +if test "x$ac_cv_header_unwind_h" = x""yes; then : + ac_fn_c_check_func "$LINENO" "_Unwind_Backtrace" "ac_cv_func__Unwind_Backtrace" +if test "x$ac_cv_func__Unwind_Backtrace" = x""yes; then : + BACKTRACE_FILE="backtrace.lo simple.lo" +else + BACKTRACE_FILE="nounwind.lo" + backtrace_supported=no +fi + +else + BACKTRACE_FILE="nounwind.lo" + backtrace_supported=no +fi + + +fi + + +EXTRA_FLAGS= +if test -n "${with_target_subdir}"; then + EXTRA_FLAGS="-funwind-tables -frandom-seed=\$@" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -funwind-tables option" >&5 +$as_echo_n "checking for -funwind-tables option... " >&6; } +if test "${libbacktrace_cv_c_unwind_tables+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + CFLAGS_hold="$CFLAGS" + CFLAGS="$CFLAGS -funwind-tables" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +static int f() { return 0; } +int +main () +{ +return f(); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + libbacktrace_cv_c_unwind_tables=yes +else + libbacktrace_cv_c_unwind_tables=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$CFLAGS_hold" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_c_unwind_tables" >&5 +$as_echo "$libbacktrace_cv_c_unwind_tables" >&6; } + if test "$libbacktrace_cv_c_unwind_tables" = "yes"; then + EXTRA_FLAGS=-funwind-tables + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -frandom-seed=string option" >&5 +$as_echo_n "checking for -frandom-seed=string option... " >&6; } +if test "${libbacktrace_cv_c_random_seed_string+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + CFLAGS_hold="$CFLAGS" + CFLAGS="$CFLAGS -frandom-seed=conftest.lo" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + libbacktrace_cv_c_random_seed_string=yes +else + libbacktrace_cv_c_random_seed_string=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CFLAGS="$CFLAGS_hold" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_c_random_seed_string" >&5 +$as_echo "$libbacktrace_cv_c_random_seed_string" >&6; } + if test "$libbacktrace_cv_c_random_seed_string" = "yes"; then + EXTRA_FLAGS="$EXTRA_FLAGS -frandom-seed=\$@" + fi +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +WARN_FLAGS= +save_CFLAGS="$CFLAGS" +for real_option in -W -Wall -Wwrite-strings -Wstrict-prototypes \ + -Wmissing-prototypes -Wold-style-definition \ + -Wmissing-format-attribute -Wcast-qual; do + # Do the check with the no- prefix removed since gcc silently + # accepts any -Wno-* option on purpose + case $real_option in + -Wno-*) option=-W`expr x$real_option : 'x-Wno-\(.*\)'` ;; + *) option=$real_option ;; + esac + as_acx_Woption=`$as_echo "acx_cv_prog_cc_warning_$option" | $as_tr_sh` + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $option" >&5 +$as_echo_n "checking whether $CC supports $option... " >&6; } +if { as_var=$as_acx_Woption; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + CFLAGS="$option" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$as_acx_Woption=yes" +else + eval "$as_acx_Woption=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +eval ac_res=\$$as_acx_Woption + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + if test `eval 'as_val=${'$as_acx_Woption'};$as_echo "$as_val"'` = yes; then : + WARN_FLAGS="$WARN_FLAGS${WARN_FLAGS:+ }$real_option" +fi + done +CFLAGS="$save_CFLAGS" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +if test -n "${with_target_subdir}"; then + WARN_FLAGS="$WARN_FLAGS -Werror" +fi + + + +if test -n "${with_target_subdir}"; then + + +# Check whether --with-system-libunwind was given. +if test "${with_system_libunwind+set}" = set; then : + withval=$with_system_libunwind; +fi + + # If system-libunwind was not specifically set, pick a default setting. + if test x$with_system_libunwind = x; then + case ${target} in + ia64-*-hpux*) with_system_libunwind=yes ;; + *) with_system_libunwind=no ;; + esac + fi + # Based on system-libunwind and target, do we have ipinfo? + if test x$with_system_libunwind = xyes; then + case ${target} in + ia64-*-*) have_unwind_getipinfo=no ;; + *) have_unwind_getipinfo=yes ;; + esac + else + # Darwin before version 9 does not have _Unwind_GetIPInfo. + + case ${target} in + *-*-darwin[3-8]|*-*-darwin[3-8].*) have_unwind_getipinfo=no ;; + *) have_unwind_getipinfo=yes ;; + esac + + fi + + if test x$have_unwind_getipinfo = xyes; then + +$as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h + + fi + +else + ac_save_CFFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Werror-implicit-function-declaration" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _Unwind_GetIPInfo" >&5 +$as_echo_n "checking for _Unwind_GetIPInfo... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include "unwind.h" + struct _Unwind_Context *context; + int ip_before_insn = 0; +int +main () +{ +return _Unwind_GetIPInfo (context, &ip_before_insn); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + have_unwind_getipinfo=yes +else + have_unwind_getipinfo=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$ac_save_CFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_unwind_getipinfo" >&5 +$as_echo "$have_unwind_getipinfo" >&6; } + if test "$have_unwind_getipinfo" = "yes"; then + +$as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h + + fi +fi + +# Enable --enable-host-shared. +# Check whether --enable-host-shared was given. +if test "${enable_host_shared+set}" = set; then : + enableval=$enable_host_shared; PIC_FLAG=-fPIC +else + PIC_FLAG= +fi + + + +# Test for __sync support. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking __sync extensions" >&5 +$as_echo_n "checking __sync extensions... " >&6; } +if test "${libbacktrace_cv_sys_sync+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "${with_target_subdir}"; then + case "${host}" in + hppa*-*-hpux*) libbacktrace_cv_sys_sync=no ;; + *) libbacktrace_cv_sys_sync=yes ;; + esac + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int i; +int +main () +{ +__sync_bool_compare_and_swap (&i, i, i); + __sync_lock_test_and_set (&i, 1); + __sync_lock_release (&i); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + libbacktrace_cv_sys_sync=yes +else + libbacktrace_cv_sys_sync=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_sys_sync" >&5 +$as_echo "$libbacktrace_cv_sys_sync" >&6; } +BACKTRACE_SUPPORTS_THREADS=0 +if test "$libbacktrace_cv_sys_sync" = "yes"; then + BACKTRACE_SUPPORTS_THREADS=1 + +$as_echo "#define HAVE_SYNC_FUNCTIONS 1" >>confdefs.h + +fi + + +# Test for __atomic support. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking __atomic extensions" >&5 +$as_echo_n "checking __atomic extensions... " >&6; } +if test "${libbacktrace_cv_sys_atomic+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "${with_target_subdir}"; then + libbacktrace_cv_sys_atomic=yes + else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int i; +int +main () +{ +__atomic_load_n (&i, __ATOMIC_ACQUIRE); + __atomic_store_n (&i, 1, __ATOMIC_RELEASE); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + libbacktrace_cv_sys_atomic=yes +else + libbacktrace_cv_sys_atomic=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_sys_atomic" >&5 +$as_echo "$libbacktrace_cv_sys_atomic" >&6; } +if test "$libbacktrace_cv_sys_atomic" = "yes"; then + +$as_echo "#define HAVE_ATOMIC_FUNCTIONS 1" >>confdefs.h + +fi + +# The library needs to be able to read the executable itself. Compile +# a file to determine the executable format. The awk script +# filetype.awk prints out the file type. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking output filetype" >&5 +$as_echo_n "checking output filetype... " >&6; } +if test "${libbacktrace_cv_sys_filetype+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + filetype= +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int i; +int +main () +{ +int j; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + filetype=`${AWK} -f $srcdir/filetype.awk conftest.$ac_objext` +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "compiler failed +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +libbacktrace_cv_sys_filetype=$filetype +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_sys_filetype" >&5 +$as_echo "$libbacktrace_cv_sys_filetype" >&6; } + +# Match the file type to decide what files to compile. +FORMAT_FILE= +backtrace_supports_data=yes +case "$libbacktrace_cv_sys_filetype" in +elf*) FORMAT_FILE="elf.lo" ;; +pecoff) FORMAT_FILE="pecoff.lo" + backtrace_supports_data=no + ;; +*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not determine output file type" >&5 +$as_echo "$as_me: WARNING: could not determine output file type" >&2;} + FORMAT_FILE="unknown.lo" + backtrace_supported=no + ;; +esac + + +# ELF defines. +elfsize= +case "$libbacktrace_cv_sys_filetype" in +elf32) elfsize=32 ;; +elf64) elfsize=64 ;; +*) elfsize=unused +esac + +cat >>confdefs.h <<_ACEOF +#define BACKTRACE_ELF_SIZE $elfsize +_ACEOF + + +BACKTRACE_SUPPORTED=0 +if test "$backtrace_supported" = "yes"; then + BACKTRACE_SUPPORTED=1 +fi + + +BACKTRACE_SUPPORTS_DATA=0 +if test "$backtrace_supports_data" = "yes"; then + BACKTRACE_SUPPORTS_DATA=1 +fi + + + + +inttype_headers=`echo inttypes.h sys/inttypes.h | sed -e 's/,/ /g'` + +acx_cv_header_stdint=stddef.h +acx_cv_header_stdint_kind="(already complete)" +for i in stdint.h $inttype_headers; do + unset ac_cv_type_uintptr_t + unset ac_cv_type_uintmax_t + unset ac_cv_type_int_least32_t + unset ac_cv_type_int_fast32_t + unset ac_cv_type_uint64_t + $as_echo_n "looking for a compliant stdint.h in $i, " >&6 + ac_fn_c_check_type "$LINENO" "uintmax_t" "ac_cv_type_uintmax_t" "#include +#include <$i> +" +if test "x$ac_cv_type_uintmax_t" = x""yes; then : + acx_cv_header_stdint=$i +else + continue +fi + + ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "#include +#include <$i> +" +if test "x$ac_cv_type_uintptr_t" = x""yes; then : + +else + acx_cv_header_stdint_kind="(mostly complete)" +fi + + ac_fn_c_check_type "$LINENO" "int_least32_t" "ac_cv_type_int_least32_t" "#include +#include <$i> +" +if test "x$ac_cv_type_int_least32_t" = x""yes; then : + +else + acx_cv_header_stdint_kind="(mostly complete)" +fi + + ac_fn_c_check_type "$LINENO" "int_fast32_t" "ac_cv_type_int_fast32_t" "#include +#include <$i> +" +if test "x$ac_cv_type_int_fast32_t" = x""yes; then : + +else + acx_cv_header_stdint_kind="(mostly complete)" +fi + + ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "#include +#include <$i> +" +if test "x$ac_cv_type_uint64_t" = x""yes; then : + +else + acx_cv_header_stdint_kind="(lacks uint64_t)" +fi + + break +done +if test "$acx_cv_header_stdint" = stddef.h; then + acx_cv_header_stdint_kind="(lacks uintmax_t)" + for i in stdint.h $inttype_headers; do + unset ac_cv_type_uintptr_t + unset ac_cv_type_uint32_t + unset ac_cv_type_uint64_t + $as_echo_n "looking for an incomplete stdint.h in $i, " >&6 + ac_fn_c_check_type "$LINENO" "uint32_t" "ac_cv_type_uint32_t" "#include +#include <$i> +" +if test "x$ac_cv_type_uint32_t" = x""yes; then : + acx_cv_header_stdint=$i +else + continue +fi + + ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "#include +#include <$i> +" +if test "x$ac_cv_type_uint64_t" = x""yes; then : + +fi + + ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "#include +#include <$i> +" +if test "x$ac_cv_type_uintptr_t" = x""yes; then : + +fi + + break + done +fi +if test "$acx_cv_header_stdint" = stddef.h; then + acx_cv_header_stdint_kind="(u_intXX_t style)" + for i in sys/types.h $inttype_headers; do + unset ac_cv_type_u_int32_t + unset ac_cv_type_u_int64_t + $as_echo_n "looking for u_intXX_t types in $i, " >&6 + ac_fn_c_check_type "$LINENO" "u_int32_t" "ac_cv_type_u_int32_t" "#include +#include <$i> +" +if test "x$ac_cv_type_u_int32_t" = x""yes; then : + acx_cv_header_stdint=$i +else + continue +fi + + ac_fn_c_check_type "$LINENO" "u_int64_t" "ac_cv_type_u_int64_t" "#include +#include <$i> +" +if test "x$ac_cv_type_u_int64_t" = x""yes; then : + +fi + + break + done +fi +if test "$acx_cv_header_stdint" = stddef.h; then + acx_cv_header_stdint_kind="(using manual detection)" +fi + +test -z "$ac_cv_type_uintptr_t" && ac_cv_type_uintptr_t=no +test -z "$ac_cv_type_uint64_t" && ac_cv_type_uint64_t=no +test -z "$ac_cv_type_u_int64_t" && ac_cv_type_u_int64_t=no +test -z "$ac_cv_type_int_least32_t" && ac_cv_type_int_least32_t=no +test -z "$ac_cv_type_int_fast32_t" && ac_cv_type_int_fast32_t=no + +# ----------------- Summarize what we found so far + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking what to include in gstdint.h" >&5 +$as_echo_n "checking what to include in gstdint.h... " >&6; } + +case `$as_basename -- gstdint.h || +$as_expr X/gstdint.h : '.*/\([^/][^/]*\)/*$' \| \ + Xgstdint.h : 'X\(//\)$' \| \ + Xgstdint.h : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/gstdint.h | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` in + stdint.h) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: are you sure you want it there?" >&5 +$as_echo "$as_me: WARNING: are you sure you want it there?" >&2;} ;; + inttypes.h) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: are you sure you want it there?" >&5 +$as_echo "$as_me: WARNING: are you sure you want it there?" >&2;} ;; + *) ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_header_stdint $acx_cv_header_stdint_kind" >&5 +$as_echo "$acx_cv_header_stdint $acx_cv_header_stdint_kind" >&6; } + +# ----------------- done included file, check C basic types -------- + +# Lacking an uintptr_t? Test size of void * +case "$acx_cv_header_stdint:$ac_cv_type_uintptr_t" in + stddef.h:* | *:no) # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 +$as_echo_n "checking size of void *... " >&6; } +if test "${ac_cv_sizeof_void_p+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_void_p" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (void *) +See \`config.log' for more details." "$LINENO" 5; }; } + else + ac_cv_sizeof_void_p=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 +$as_echo "$ac_cv_sizeof_void_p" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_VOID_P $ac_cv_sizeof_void_p +_ACEOF + + ;; +esac + +# Lacking an uint64_t? Test size of long +case "$acx_cv_header_stdint:$ac_cv_type_uint64_t:$ac_cv_type_u_int64_t" in + stddef.h:*:* | *:no:no) # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 +$as_echo_n "checking size of long... " >&6; } +if test "${ac_cv_sizeof_long+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_long" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (long) +See \`config.log' for more details." "$LINENO" 5; }; } + else + ac_cv_sizeof_long=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 +$as_echo "$ac_cv_sizeof_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG $ac_cv_sizeof_long +_ACEOF + + ;; +esac + +if test $acx_cv_header_stdint = stddef.h; then + # Lacking a good header? Test size of everything and deduce all types. + # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 +$as_echo_n "checking size of int... " >&6; } +if test "${ac_cv_sizeof_int+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_int" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (int) +See \`config.log' for more details." "$LINENO" 5; }; } + else + ac_cv_sizeof_int=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 +$as_echo "$ac_cv_sizeof_int" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_INT $ac_cv_sizeof_int +_ACEOF + + + # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 +$as_echo_n "checking size of short... " >&6; } +if test "${ac_cv_sizeof_short+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_short" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (short) +See \`config.log' for more details." "$LINENO" 5; }; } + else + ac_cv_sizeof_short=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 +$as_echo "$ac_cv_sizeof_short" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_SHORT $ac_cv_sizeof_short +_ACEOF + + + # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char" >&5 +$as_echo_n "checking size of char... " >&6; } +if test "${ac_cv_sizeof_char+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char))" "ac_cv_sizeof_char" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_char" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (char) +See \`config.log' for more details." "$LINENO" 5; }; } + else + ac_cv_sizeof_char=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char" >&5 +$as_echo "$ac_cv_sizeof_char" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_CHAR $ac_cv_sizeof_char +_ACEOF + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to int8_t" >&5 +$as_echo_n "checking for type equivalent to int8_t... " >&6; } + case "$ac_cv_sizeof_char" in + 1) acx_cv_type_int8_t=char ;; + *) as_fn_error "no 8-bit type, please report a bug" "$LINENO" 5 + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_type_int8_t" >&5 +$as_echo "$acx_cv_type_int8_t" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to int16_t" >&5 +$as_echo_n "checking for type equivalent to int16_t... " >&6; } + case "$ac_cv_sizeof_int:$ac_cv_sizeof_short" in + 2:*) acx_cv_type_int16_t=int ;; + *:2) acx_cv_type_int16_t=short ;; + *) as_fn_error "no 16-bit type, please report a bug" "$LINENO" 5 + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_type_int16_t" >&5 +$as_echo "$acx_cv_type_int16_t" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to int32_t" >&5 +$as_echo_n "checking for type equivalent to int32_t... " >&6; } + case "$ac_cv_sizeof_int:$ac_cv_sizeof_long" in + 4:*) acx_cv_type_int32_t=int ;; + *:4) acx_cv_type_int32_t=long ;; + *) as_fn_error "no 32-bit type, please report a bug" "$LINENO" 5 + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_type_int32_t" >&5 +$as_echo "$acx_cv_type_int32_t" >&6; } +fi + +# These tests are here to make the output prettier + +if test "$ac_cv_type_uint64_t" != yes && test "$ac_cv_type_u_int64_t" != yes; then + case "$ac_cv_sizeof_long" in + 8) acx_cv_type_int64_t=long ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to int64_t" >&5 +$as_echo_n "checking for type equivalent to int64_t... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${acx_cv_type_int64_t-'using preprocessor symbols'}" >&5 +$as_echo "${acx_cv_type_int64_t-'using preprocessor symbols'}" >&6; } +fi + +# Now we can use the above types + +if test "$ac_cv_type_uintptr_t" != yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to intptr_t" >&5 +$as_echo_n "checking for type equivalent to intptr_t... " >&6; } + case $ac_cv_sizeof_void_p in + 2) acx_cv_type_intptr_t=int16_t ;; + 4) acx_cv_type_intptr_t=int32_t ;; + 8) acx_cv_type_intptr_t=int64_t ;; + *) as_fn_error "no equivalent for intptr_t, please report a bug" "$LINENO" 5 + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_type_intptr_t" >&5 +$as_echo "$acx_cv_type_intptr_t" >&6; } +fi + +# ----------------- done all checks, emit header ------------- +ac_config_commands="$ac_config_commands gstdint.h" + + + + +for ac_header in sys/mman.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_mman_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_MMAN_H 1 +_ACEOF + +fi + +done + +if test "$ac_cv_header_sys_mman_h" = "no"; then + have_mmap=no +else + if test -n "${with_target_subdir}"; then + # When built as a GCC target library, we can't do a link test. We + # simply assume that if we have mman.h, we have mmap. + have_mmap=yes + case "${host}" in + spu-*-*|*-*-msdosdjgpp) + # The SPU does not have mmap, but it has a sys/mman.h header file + # containing "mmap_eaddr" and the mmap flags, confusing the test. + # DJGPP also has sys/man.h, but no mmap + have_mmap=no ;; + esac + else + ac_fn_c_check_func "$LINENO" "mmap" "ac_cv_func_mmap" +if test "x$ac_cv_func_mmap" = x""yes; then : + have_mmap=yes +else + have_mmap=no +fi + + fi +fi +if test "$have_mmap" = "no"; then + VIEW_FILE=read.lo + ALLOC_FILE=alloc.lo +else + VIEW_FILE=mmapio.lo + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#if !defined(MAP_ANONYMOUS) && !defined(MAP_ANON) + #error no MAP_ANONYMOUS +#endif + +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ALLOC_FILE=alloc.lo +else + ALLOC_FILE=alloc.lo +fi +rm -f conftest.err conftest.$ac_ext +fi + + + +BACKTRACE_USES_MALLOC=0 +if test "$ALLOC_FILE" = "alloc.lo"; then + BACKTRACE_USES_MALLOC=1 +fi + + +# Check for dl_iterate_phdr. +for ac_header in link.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "link.h" "ac_cv_header_link_h" "$ac_includes_default" +if test "x$ac_cv_header_link_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LINK_H 1 +_ACEOF + +fi + +done + +if test "$ac_cv_header_link_h" = "no"; then + have_dl_iterate_phdr=no +else + if test -n "${with_target_subdir}"; then + # When built as a GCC target library, we can't do a link test. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "dl_iterate_phdr" >/dev/null 2>&1; then : + have_dl_iterate_phdr=yes +else + have_dl_iterate_phdr=no +fi +rm -f conftest* + + case "${host}" in + *-*-solaris2.10*) + # Avoid dl_iterate_phdr on Solaris 10, where it is in the + # header file but is only in -ldl. + have_dl_iterate_phdr=no ;; + esac + else + ac_fn_c_check_func "$LINENO" "dl_iterate_phdr" "ac_cv_func_dl_iterate_phdr" +if test "x$ac_cv_func_dl_iterate_phdr" = x""yes; then : + have_dl_iterate_phdr=yes +else + have_dl_iterate_phdr=no +fi + + fi +fi +if test "$have_dl_iterate_phdr" = "yes"; then + +$as_echo "#define HAVE_DL_ITERATE_PHDR 1" >>confdefs.h + +fi + +# Check for the fcntl function. +if test -n "${with_target_subdir}"; then + case "${host}" in + *-*-mingw*) have_fcntl=no ;; + spu-*-*) have_fcntl=no ;; + *) have_fcntl=yes ;; + esac +else + ac_fn_c_check_func "$LINENO" "fcntl" "ac_cv_func_fcntl" +if test "x$ac_cv_func_fcntl" = x""yes; then : + have_fcntl=yes +else + have_fcntl=no +fi + +fi +if test "$have_fcntl" = "yes"; then + +$as_echo "#define HAVE_FCNTL 1" >>confdefs.h + +fi + +ac_fn_c_check_decl "$LINENO" "strnlen" "ac_cv_have_decl_strnlen" "$ac_includes_default" +if test "x$ac_cv_have_decl_strnlen" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRNLEN $ac_have_decl +_ACEOF + + +# Check for getexecname function. +if test -n "${with_target_subdir}"; then + case "${host}" in + *-*-solaris2*) have_getexecname=yes ;; + *) have_getexecname=no ;; + esac +else + ac_fn_c_check_func "$LINENO" "getexecname" "ac_cv_func_getexecname" +if test "x$ac_cv_func_getexecname" = x""yes; then : + have_getexecname=yes +else + have_getexecname=no +fi + +fi +if test "$have_getexecname" = "yes"; then + +$as_echo "#define HAVE_GETEXECNAME 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tests can run" >&5 +$as_echo_n "checking whether tests can run... " >&6; } +if test "${libbacktrace_cv_sys_native+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + libbacktrace_cv_sys_native=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + libbacktrace_cv_sys_native=yes +else + libbacktrace_cv_sys_native=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_sys_native" >&5 +$as_echo "$libbacktrace_cv_sys_native" >&6; } + if test "$libbacktrace_cv_sys_native" = "yes"; then + NATIVE_TRUE= + NATIVE_FALSE='#' +else + NATIVE_TRUE='#' + NATIVE_FALSE= +fi + + +if test "${multilib}" = "yes"; then + multilib_arg="--enable-multilib" +else + multilib_arg= +fi + +ac_config_files="$ac_config_files Makefile backtrace-supported.h" + + +# We need multilib support, but only if configuring for the target. +ac_config_commands="$ac_config_commands default" + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${NATIVE_TRUE}" && test -z "${NATIVE_FALSE}"; then + as_fn_error "conditional \"NATIVE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by package-unused $as_me version-unused, which was +generated by GNU Autoconf 2.64. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_version="\\ +package-unused config.status version-unused +configured by $0, generated by GNU Autoconf 2.64, + with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2009 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# + +srcdir="$srcdir" +host="$host" +target="$target" +with_multisubdir="$with_multisubdir" +with_multisrctop="$with_multisrctop" +with_target_subdir="$with_target_subdir" +ac_configure_args="${multilib_arg} ${ac_configure_args}" +multi_basedir="$multi_basedir" +CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} +CC="$CC" +CXX="$CXX" +GFORTRAN="$GFORTRAN" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +AR \ +AR_FLAGS \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_wl \ +lt_prog_compiler_pic \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_flag_spec_ld \ +hardcode_libdir_separator \ +fix_srcfile_path \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + +GCC="$GCC" +CC="$CC" +acx_cv_header_stdint="$acx_cv_header_stdint" +acx_cv_type_int8_t="$acx_cv_type_int8_t" +acx_cv_type_int16_t="$acx_cv_type_int16_t" +acx_cv_type_int32_t="$acx_cv_type_int32_t" +acx_cv_type_int64_t="$acx_cv_type_int64_t" +acx_cv_type_intptr_t="$acx_cv_type_intptr_t" +ac_cv_type_uintmax_t="$ac_cv_type_uintmax_t" +ac_cv_type_uintptr_t="$ac_cv_type_uintptr_t" +ac_cv_type_uint64_t="$ac_cv_type_uint64_t" +ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t" +ac_cv_type_u_int32_t="$ac_cv_type_u_int32_t" +ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t" +ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t" +ac_cv_sizeof_void_p="$ac_cv_sizeof_void_p" + + +# Variables needed in config.status (file generation) which aren't already +# passed by autoconf. +SUBDIRS="$SUBDIRS" + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "gstdint.h") CONFIG_COMMANDS="$CONFIG_COMMANDS gstdint.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "backtrace-supported.h") CONFIG_FILES="$CONFIG_FILES backtrace-supported.h" ;; + "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;; + + *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\).*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\).*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_t"; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$tmp/config.h" "$ac_file" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "default-1":C) +# Only add multilib support code if we just rebuilt the top-level +# Makefile. +case " $CONFIG_FILES " in + *" Makefile "*) + ac_file=Makefile . ${multi_basedir}/config-ml.in + ;; +esac ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="" + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method == "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# The archiver. +AR=$lt_AR +AR_FLAGS=$lt_AR_FLAGS + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# If ld is used when linking, flag to hardcode \$libdir into a binary +# during linking. This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path=$lt_fix_srcfile_path + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + case $xsi_shell in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac +} + +# func_basename file +func_basename () +{ + func_basename_result="${1##*/}" +} + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}" +} + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +func_stripname () +{ + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"} +} + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=${1%%=*} + func_opt_split_arg=${1#*=} +} + +# func_lo2o object +func_lo2o () +{ + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=${1%.*}.lo +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=$(( $* )) +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=${#1} +} + +_LT_EOF + ;; + *) # Bourne compatible functions. + cat << \_LT_EOF >> "$cfgfile" + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} + +# sed scripts: +my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' +my_sed_long_arg='1s/^-[^=]*=//' + +# func_opt_split +func_opt_split () +{ + func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"` + func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"` +} + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "$@"` +} + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` +} + +_LT_EOF +esac + +case $lt_shell_append in + yes) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1+=\$2" +} +_LT_EOF + ;; + *) + cat << \_LT_EOF >> "$cfgfile" + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "$1=\$$1\$2" +} + +_LT_EOF + ;; + esac + + + sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + ;; + "gstdint.h":C) +if test "$GCC" = yes; then + echo "/* generated for " `$CC --version | sed 1q` "*/" > tmp-stdint.h +else + echo "/* generated for $CC */" > tmp-stdint.h +fi + +sed 's/^ *//' >> tmp-stdint.h < +EOF + +if test "$acx_cv_header_stdint" != stdint.h; then + echo "#include " >> tmp-stdint.h +fi +if test "$acx_cv_header_stdint" != stddef.h; then + echo "#include <$acx_cv_header_stdint>" >> tmp-stdint.h +fi + +sed 's/^ *//' >> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <= 199901L + #ifndef _INT64_T + #define _INT64_T + #ifndef __int64_t_defined + #ifndef int64_t + typedef long long int64_t; + #endif + #endif + #endif + #ifndef _UINT64_T + #define _UINT64_T + #ifndef uint64_t + typedef unsigned long long uint64_t; + #endif + #endif + + #elif defined __GNUC__ && defined (__STDC__) && __STDC__-0 + /* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and + does not implement __extension__. But that compiler doesn't define + __GNUC_MINOR__. */ + # if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__) + # define __extension__ + # endif + + # ifndef _INT64_T + # define _INT64_T + # ifndef int64_t + __extension__ typedef long long int64_t; + # endif + # endif + # ifndef _UINT64_T + # define _UINT64_T + # ifndef uint64_t + __extension__ typedef unsigned long long uint64_t; + # endif + # endif + + #elif !defined __STRICT_ANSI__ + # if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ + + # ifndef _INT64_T + # define _INT64_T + # ifndef int64_t + typedef __int64 int64_t; + # endif + # endif + # ifndef _UINT64_T + # define _UINT64_T + # ifndef uint64_t + typedef unsigned __int64 uint64_t; + # endif + # endif + # endif /* compiler */ + + #endif /* ANSI version */ +EOF +fi + +# ------------- done int64_t types, emit intptr types ------------ +if test "$ac_cv_type_uintptr_t" != yes; then + sed 's/^ *//' >> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h < + # srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually + # append it here. Only modify Makefiles that have just been created. + # + # Also, get rid of this simulated-VPATH thing that automake does. + cat > vpsed << \_EOF + s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + for i in $SUBDIRS; do + case $CONFIG_FILES in + *${i}/Makefile*) + #echo "Adding MULTISUBDIR to $i/Makefile" + sed -f vpsed $i/Makefile > tmp + grep '^MULTISUBDIR =' Makefile >> tmp + mv tmp $i/Makefile + ;; + esac + done + rm vpsed + fi + fi + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit $? +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/backtrace-sys-0.1.16/src/libbacktrace/configure.ac b/backtrace-sys-0.1.16/src/libbacktrace/configure.ac new file mode 100644 index 000000000..2b774b058 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/configure.ac @@ -0,0 +1,409 @@ +# configure.ac -- Backtrace configure script. +# Copyright (C) 2012-2016 Free Software Foundation, Inc. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: + +# (1) Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. + +# (2) Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. + +# (3) The name of the author may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +AC_PREREQ(2.64) +AC_INIT(package-unused, version-unused,, libbacktrace) +AC_CONFIG_SRCDIR(backtrace.h) +AC_CONFIG_HEADER(config.h) + +if test -n "${with_target_subdir}"; then + AM_ENABLE_MULTILIB(, ..) +fi + +AC_CANONICAL_SYSTEM +target_alias=${target_alias-$host_alias} + +AC_USE_SYSTEM_EXTENSIONS + +libtool_VERSION=1:0:0 +AC_SUBST(libtool_VERSION) + +# 1.11.1: Require that version of automake. +# foreign: Don't require README, INSTALL, NEWS, etc. +# no-define: Don't define PACKAGE and VERSION. +# no-dependencies: Don't generate automatic dependencies. +# (because it breaks when using bootstrap-lean, since some of the +# headers are gone at "make install" time). +# -Wall: Issue all automake warnings. +# -Wno-portability: Don't warn about constructs supported by GNU make. +# (because GCC requires GNU make anyhow). +AM_INIT_AUTOMAKE([1.11.1 foreign no-dist no-define no-dependencies -Wall -Wno-portability]) + +AM_MAINTAINER_MODE + +AC_ARG_WITH(target-subdir, +[ --with-target-subdir=SUBDIR Configuring in a subdirectory for target]) + +# We must force CC to /not/ be precious variables; otherwise +# the wrong, non-multilib-adjusted value will be used in multilibs. +# As a side effect, we have to subst CFLAGS ourselves. +m4_rename([_AC_ARG_VAR_PRECIOUS],[backtrace_PRECIOUS]) +m4_define([_AC_ARG_VAR_PRECIOUS],[]) +AC_PROG_CC +m4_rename_force([backtrace_PRECIOUS],[_AC_ARG_VAR_PRECIOUS]) + +AC_SUBST(CFLAGS) + +AC_PROG_RANLIB + +AC_PROG_AWK +case "$AWK" in +"") AC_MSG_ERROR([can't build without awk]) ;; +esac + +LT_INIT +AM_PROG_LIBTOOL + +backtrace_supported=yes + +if test -n "${with_target_subdir}"; then + # We are compiling a GCC library. We can assume that the unwind + # library exists. + BACKTRACE_FILE="backtrace.lo simple.lo" +else + AC_CHECK_HEADER([unwind.h], + [AC_CHECK_FUNC([_Unwind_Backtrace], + [BACKTRACE_FILE="backtrace.lo simple.lo"], + [BACKTRACE_FILE="nounwind.lo" + backtrace_supported=no])], + [BACKTRACE_FILE="nounwind.lo" + backtrace_supported=no]) +fi +AC_SUBST(BACKTRACE_FILE) + +EXTRA_FLAGS= +if test -n "${with_target_subdir}"; then + EXTRA_FLAGS="-funwind-tables -frandom-seed=\$@" +else + AC_CACHE_CHECK([for -funwind-tables option], + [libbacktrace_cv_c_unwind_tables], + [CFLAGS_hold="$CFLAGS" + CFLAGS="$CFLAGS -funwind-tables" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([static int f() { return 0; }], [return f();])], + [libbacktrace_cv_c_unwind_tables=yes], + [libbacktrace_cv_c_unwind_tables=no]) + CFLAGS="$CFLAGS_hold"]) + if test "$libbacktrace_cv_c_unwind_tables" = "yes"; then + EXTRA_FLAGS=-funwind-tables + fi + AC_CACHE_CHECK([for -frandom-seed=string option], + [libbacktrace_cv_c_random_seed_string], + [CFLAGS_hold="$CFLAGS" + CFLAGS="$CFLAGS -frandom-seed=conftest.lo" + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([], [return 0;])], + [libbacktrace_cv_c_random_seed_string=yes], + [libbacktrace_cv_c_random_seed_string=no]) + CFLAGS="$CFLAGS_hold"]) + if test "$libbacktrace_cv_c_random_seed_string" = "yes"; then + EXTRA_FLAGS="$EXTRA_FLAGS -frandom-seed=\$@" + fi +fi +AC_SUBST(EXTRA_FLAGS) + +ACX_PROG_CC_WARNING_OPTS([-W -Wall -Wwrite-strings -Wstrict-prototypes \ + -Wmissing-prototypes -Wold-style-definition \ + -Wmissing-format-attribute -Wcast-qual], + [WARN_FLAGS]) + +if test -n "${with_target_subdir}"; then + WARN_FLAGS="$WARN_FLAGS -Werror" +fi + +AC_SUBST(WARN_FLAGS) + +if test -n "${with_target_subdir}"; then + GCC_CHECK_UNWIND_GETIPINFO +else + ac_save_CFFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Werror-implicit-function-declaration" + AC_MSG_CHECKING([for _Unwind_GetIPInfo]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [#include "unwind.h" + struct _Unwind_Context *context; + int ip_before_insn = 0;], + [return _Unwind_GetIPInfo (context, &ip_before_insn);])], + [have_unwind_getipinfo=yes], [have_unwind_getipinfo=no]) + CFLAGS="$ac_save_CFLAGS" + AC_MSG_RESULT([$have_unwind_getipinfo]) + if test "$have_unwind_getipinfo" = "yes"; then + AC_DEFINE(HAVE_GETIPINFO, 1, [Define if _Unwind_GetIPInfo is available.]) + fi +fi + +# Enable --enable-host-shared. +AC_ARG_ENABLE(host-shared, +[AS_HELP_STRING([--enable-host-shared], + [build host code as shared libraries])], +[PIC_FLAG=-fPIC], [PIC_FLAG=]) +AC_SUBST(PIC_FLAG) + +# Test for __sync support. +AC_CACHE_CHECK([__sync extensions], +[libbacktrace_cv_sys_sync], +[if test -n "${with_target_subdir}"; then + case "${host}" in + hppa*-*-hpux*) libbacktrace_cv_sys_sync=no ;; + *) libbacktrace_cv_sys_sync=yes ;; + esac + else + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([int i;], + [__sync_bool_compare_and_swap (&i, i, i); + __sync_lock_test_and_set (&i, 1); + __sync_lock_release (&i);])], + [libbacktrace_cv_sys_sync=yes], + [libbacktrace_cv_sys_sync=no]) + fi]) +BACKTRACE_SUPPORTS_THREADS=0 +if test "$libbacktrace_cv_sys_sync" = "yes"; then + BACKTRACE_SUPPORTS_THREADS=1 + AC_DEFINE([HAVE_SYNC_FUNCTIONS], 1, + [Define to 1 if you have the __sync functions]) +fi +AC_SUBST(BACKTRACE_SUPPORTS_THREADS) + +# Test for __atomic support. +AC_CACHE_CHECK([__atomic extensions], +[libbacktrace_cv_sys_atomic], +[if test -n "${with_target_subdir}"; then + libbacktrace_cv_sys_atomic=yes + else + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([int i;], + [__atomic_load_n (&i, __ATOMIC_ACQUIRE); + __atomic_store_n (&i, 1, __ATOMIC_RELEASE);])], + [libbacktrace_cv_sys_atomic=yes], + [libbacktrace_cv_sys_atomic=no]) + fi]) +if test "$libbacktrace_cv_sys_atomic" = "yes"; then + AC_DEFINE([HAVE_ATOMIC_FUNCTIONS], 1, + [Define to 1 if you have the __atomic functions]) +fi + +# The library needs to be able to read the executable itself. Compile +# a file to determine the executable format. The awk script +# filetype.awk prints out the file type. +AC_CACHE_CHECK([output filetype], +[libbacktrace_cv_sys_filetype], +[filetype= +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([int i;], [int j;])], + [filetype=`${AWK} -f $srcdir/filetype.awk conftest.$ac_objext`], + [AC_MSG_FAILURE([compiler failed])]) +libbacktrace_cv_sys_filetype=$filetype]) + +# Match the file type to decide what files to compile. +FORMAT_FILE= +backtrace_supports_data=yes +case "$libbacktrace_cv_sys_filetype" in +elf*) FORMAT_FILE="elf.lo" ;; +pecoff) FORMAT_FILE="pecoff.lo" + backtrace_supports_data=no + ;; +*) AC_MSG_WARN([could not determine output file type]) + FORMAT_FILE="unknown.lo" + backtrace_supported=no + ;; +esac +AC_SUBST(FORMAT_FILE) + +# ELF defines. +elfsize= +case "$libbacktrace_cv_sys_filetype" in +elf32) elfsize=32 ;; +elf64) elfsize=64 ;; +*) elfsize=unused +esac +AC_DEFINE_UNQUOTED([BACKTRACE_ELF_SIZE], [$elfsize], [ELF size: 32 or 64]) + +BACKTRACE_SUPPORTED=0 +if test "$backtrace_supported" = "yes"; then + BACKTRACE_SUPPORTED=1 +fi +AC_SUBST(BACKTRACE_SUPPORTED) + +BACKTRACE_SUPPORTS_DATA=0 +if test "$backtrace_supports_data" = "yes"; then + BACKTRACE_SUPPORTS_DATA=1 +fi +AC_SUBST(BACKTRACE_SUPPORTS_DATA) + +GCC_HEADER_STDINT(gstdint.h) + +AC_CHECK_HEADERS(sys/mman.h) +if test "$ac_cv_header_sys_mman_h" = "no"; then + have_mmap=no +else + if test -n "${with_target_subdir}"; then + # When built as a GCC target library, we can't do a link test. We + # simply assume that if we have mman.h, we have mmap. + have_mmap=yes + case "${host}" in + spu-*-*|*-*-msdosdjgpp) + # The SPU does not have mmap, but it has a sys/mman.h header file + # containing "mmap_eaddr" and the mmap flags, confusing the test. + # DJGPP also has sys/man.h, but no mmap + have_mmap=no ;; + esac + else + AC_CHECK_FUNC(mmap, [have_mmap=yes], [have_mmap=no]) + fi +fi +if test "$have_mmap" = "no"; then + VIEW_FILE=read.lo + ALLOC_FILE=alloc.lo +else + VIEW_FILE=mmapio.lo + AC_PREPROC_IFELSE([ +#include +#if !defined(MAP_ANONYMOUS) && !defined(MAP_ANON) + #error no MAP_ANONYMOUS +#endif +], [ALLOC_FILE=mmap.lo], [ALLOC_FILE=alloc.lo]) +fi +AC_SUBST(VIEW_FILE) +AC_SUBST(ALLOC_FILE) + +BACKTRACE_USES_MALLOC=0 +if test "$ALLOC_FILE" = "alloc.lo"; then + BACKTRACE_USES_MALLOC=1 +fi +AC_SUBST(BACKTRACE_USES_MALLOC) + +# Check for dl_iterate_phdr. +AC_CHECK_HEADERS(link.h) +if test "$ac_cv_header_link_h" = "no"; then + have_dl_iterate_phdr=no +else + if test -n "${with_target_subdir}"; then + # When built as a GCC target library, we can't do a link test. + AC_EGREP_HEADER([dl_iterate_phdr], [link.h], [have_dl_iterate_phdr=yes], + [have_dl_iterate_phdr=no]) + case "${host}" in + *-*-solaris2.10*) + # Avoid dl_iterate_phdr on Solaris 10, where it is in the + # header file but is only in -ldl. + have_dl_iterate_phdr=no ;; + esac + else + AC_CHECK_FUNC([dl_iterate_phdr], [have_dl_iterate_phdr=yes], + [have_dl_iterate_phdr=no]) + fi +fi +if test "$have_dl_iterate_phdr" = "yes"; then + AC_DEFINE(HAVE_DL_ITERATE_PHDR, 1, [Define if dl_iterate_phdr is available.]) +fi + +# Check for the fcntl function. +if test -n "${with_target_subdir}"; then + case "${host}" in + *-*-mingw*) have_fcntl=no ;; + spu-*-*) have_fcntl=no ;; + *) have_fcntl=yes ;; + esac +else + AC_CHECK_FUNC(fcntl, [have_fcntl=yes], [have_fcntl=no]) +fi +if test "$have_fcntl" = "yes"; then + AC_DEFINE([HAVE_FCNTL], 1, + [Define to 1 if you have the fcntl function]) +fi + +AC_CHECK_DECLS(strnlen) + +# Check for getexecname function. +if test -n "${with_target_subdir}"; then + case "${host}" in + *-*-solaris2*) have_getexecname=yes ;; + *) have_getexecname=no ;; + esac +else + AC_CHECK_FUNC(getexecname, [have_getexecname=yes], [have_getexecname=no]) +fi +if test "$have_getexecname" = "yes"; then + AC_DEFINE(HAVE_GETEXECNAME, 1, [Define if getexecname is available.]) +fi + +AC_CACHE_CHECK([whether tests can run], + [libbacktrace_cv_sys_native], + [AC_RUN_IFELSE([AC_LANG_PROGRAM([], [return 0;])], + [libbacktrace_cv_sys_native=yes], + [libbacktrace_cv_sys_native=no], + [libbacktrace_cv_sys_native=no])]) +AM_CONDITIONAL(NATIVE, test "$libbacktrace_cv_sys_native" = "yes") + +if test "${multilib}" = "yes"; then + multilib_arg="--enable-multilib" +else + multilib_arg= +fi + +AC_CONFIG_FILES(Makefile backtrace-supported.h) + +# We need multilib support, but only if configuring for the target. +AC_CONFIG_COMMANDS([default], +[if test -n "$CONFIG_FILES"; then + if test -n "${with_target_subdir}"; then + # Multilibs need MULTISUBDIR defined correctly in certain makefiles so + # that multilib installs will end up installed in the correct place. + # The testsuite needs it for multilib-aware ABI baseline files. + # To work around this not being passed down from config-ml.in -> + # srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually + # append it here. Only modify Makefiles that have just been created. + # + # Also, get rid of this simulated-VPATH thing that automake does. + cat > vpsed << \_EOF + s!`test -f '$<' || echo '$(srcdir)/'`!! +_EOF + for i in $SUBDIRS; do + case $CONFIG_FILES in + *${i}/Makefile*) + #echo "Adding MULTISUBDIR to $i/Makefile" + sed -f vpsed $i/Makefile > tmp + grep '^MULTISUBDIR =' Makefile >> tmp + mv tmp $i/Makefile + ;; + esac + done + rm vpsed + fi + fi +], +[ +# Variables needed in config.status (file generation) which aren't already +# passed by autoconf. +SUBDIRS="$SUBDIRS" +]) + +AC_OUTPUT diff --git a/backtrace-sys-0.1.16/src/libbacktrace/dwarf.c b/backtrace-sys-0.1.16/src/libbacktrace/dwarf.c new file mode 100644 index 000000000..37682c003 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/dwarf.c @@ -0,0 +1,3038 @@ +/* dwarf.c -- Get file/line information from DWARF for backtraces. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include +#include +#include + +#include "dwarf2.h" +#include "filenames.h" + +#include "backtrace.h" +#include "internal.h" + +#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN + +/* If strnlen is not declared, provide our own version. */ + +static size_t +xstrnlen (const char *s, size_t maxlen) +{ + size_t i; + + for (i = 0; i < maxlen; ++i) + if (s[i] == '\0') + break; + return i; +} + +#define strnlen xstrnlen + +#endif + +/* A buffer to read DWARF info. */ + +struct dwarf_buf +{ + /* Buffer name for error messages. */ + const char *name; + /* Start of the buffer. */ + const unsigned char *start; + /* Next byte to read. */ + const unsigned char *buf; + /* The number of bytes remaining. */ + size_t left; + /* Whether the data is big-endian. */ + int is_bigendian; + /* Error callback routine. */ + backtrace_error_callback error_callback; + /* Data for error_callback. */ + void *data; + /* Non-zero if we've reported an underflow error. */ + int reported_underflow; +}; + +/* A single attribute in a DWARF abbreviation. */ + +struct attr +{ + /* The attribute name. */ + enum dwarf_attribute name; + /* The attribute form. */ + enum dwarf_form form; +}; + +/* A single DWARF abbreviation. */ + +struct abbrev +{ + /* The abbrev code--the number used to refer to the abbrev. */ + uint64_t code; + /* The entry tag. */ + enum dwarf_tag tag; + /* Non-zero if this abbrev has child entries. */ + int has_children; + /* The number of attributes. */ + size_t num_attrs; + /* The attributes. */ + struct attr *attrs; +}; + +/* The DWARF abbreviations for a compilation unit. This structure + only exists while reading the compilation unit. Most DWARF readers + seem to a hash table to map abbrev ID's to abbrev entries. + However, we primarily care about GCC, and GCC simply issues ID's in + numerical order starting at 1. So we simply keep a sorted vector, + and try to just look up the code. */ + +struct abbrevs +{ + /* The number of abbrevs in the vector. */ + size_t num_abbrevs; + /* The abbrevs, sorted by the code field. */ + struct abbrev *abbrevs; +}; + +/* The different kinds of attribute values. */ + +enum attr_val_encoding +{ + /* An address. */ + ATTR_VAL_ADDRESS, + /* A unsigned integer. */ + ATTR_VAL_UINT, + /* A sigd integer. */ + ATTR_VAL_SINT, + /* A string. */ + ATTR_VAL_STRING, + /* An offset to other data in the containing unit. */ + ATTR_VAL_REF_UNIT, + /* An offset to other data within the .dwarf_info section. */ + ATTR_VAL_REF_INFO, + /* An offset to data in some other section. */ + ATTR_VAL_REF_SECTION, + /* A type signature. */ + ATTR_VAL_REF_TYPE, + /* A block of data (not represented). */ + ATTR_VAL_BLOCK, + /* An expression (not represented). */ + ATTR_VAL_EXPR, +}; + +/* An attribute value. */ + +struct attr_val +{ + /* How the value is stored in the field u. */ + enum attr_val_encoding encoding; + union + { + /* ATTR_VAL_ADDRESS, ATTR_VAL_UINT, ATTR_VAL_REF*. */ + uint64_t uint; + /* ATTR_VAL_SINT. */ + int64_t sint; + /* ATTR_VAL_STRING. */ + const char *string; + /* ATTR_VAL_BLOCK not stored. */ + } u; +}; + +/* The line number program header. */ + +struct line_header +{ + /* The version of the line number information. */ + int version; + /* The minimum instruction length. */ + unsigned int min_insn_len; + /* The maximum number of ops per instruction. */ + unsigned int max_ops_per_insn; + /* The line base for special opcodes. */ + int line_base; + /* The line range for special opcodes. */ + unsigned int line_range; + /* The opcode base--the first special opcode. */ + unsigned int opcode_base; + /* Opcode lengths, indexed by opcode - 1. */ + const unsigned char *opcode_lengths; + /* The number of directory entries. */ + size_t dirs_count; + /* The directory entries. */ + const char **dirs; + /* The number of filenames. */ + size_t filenames_count; + /* The filenames. */ + const char **filenames; +}; + +/* Map a single PC value to a file/line. We will keep a vector of + these sorted by PC value. Each file/line will be correct from the + PC up to the PC of the next entry if there is one. We allocate one + extra entry at the end so that we can use bsearch. */ + +struct line +{ + /* PC. */ + uintptr_t pc; + /* File name. Many entries in the array are expected to point to + the same file name. */ + const char *filename; + /* Line number. */ + int lineno; + /* Index of the object in the original array read from the DWARF + section, before it has been sorted. The index makes it possible + to use Quicksort and maintain stability. */ + int idx; +}; + +/* A growable vector of line number information. This is used while + reading the line numbers. */ + +struct line_vector +{ + /* Memory. This is an array of struct line. */ + struct backtrace_vector vec; + /* Number of valid mappings. */ + size_t count; +}; + +/* A function described in the debug info. */ + +struct function +{ + /* The name of the function. */ + const char *name; + /* If this is an inlined function, the filename of the call + site. */ + const char *caller_filename; + /* If this is an inlined function, the line number of the call + site. */ + int caller_lineno; + /* Map PC ranges to inlined functions. */ + struct function_addrs *function_addrs; + size_t function_addrs_count; +}; + +/* An address range for a function. This maps a PC value to a + specific function. */ + +struct function_addrs +{ + /* Range is LOW <= PC < HIGH. */ + uint64_t low; + uint64_t high; + /* Function for this address range. */ + struct function *function; +}; + +/* A growable vector of function address ranges. */ + +struct function_vector +{ + /* Memory. This is an array of struct function_addrs. */ + struct backtrace_vector vec; + /* Number of address ranges present. */ + size_t count; +}; + +/* A DWARF compilation unit. This only holds the information we need + to map a PC to a file and line. */ + +struct unit +{ + /* The first entry for this compilation unit. */ + const unsigned char *unit_data; + /* The length of the data for this compilation unit. */ + size_t unit_data_len; + /* The offset of UNIT_DATA from the start of the information for + this compilation unit. */ + size_t unit_data_offset; + /* DWARF version. */ + int version; + /* Whether unit is DWARF64. */ + int is_dwarf64; + /* Address size. */ + int addrsize; + /* Offset into line number information. */ + off_t lineoff; + /* Primary source file. */ + const char *filename; + /* Compilation command working directory. */ + const char *comp_dir; + /* Absolute file name, only set if needed. */ + const char *abs_filename; + /* The abbreviations for this unit. */ + struct abbrevs abbrevs; + + /* The fields above this point are read in during initialization and + may be accessed freely. The fields below this point are read in + as needed, and therefore require care, as different threads may + try to initialize them simultaneously. */ + + /* PC to line number mapping. This is NULL if the values have not + been read. This is (struct line *) -1 if there was an error + reading the values. */ + struct line *lines; + /* Number of entries in lines. */ + size_t lines_count; + /* PC ranges to function. */ + struct function_addrs *function_addrs; + size_t function_addrs_count; +}; + +/* An address range for a compilation unit. This maps a PC value to a + specific compilation unit. Note that we invert the representation + in DWARF: instead of listing the units and attaching a list of + ranges, we list the ranges and have each one point to the unit. + This lets us do a binary search to find the unit. */ + +struct unit_addrs +{ + /* Range is LOW <= PC < HIGH. */ + uint64_t low; + uint64_t high; + /* Compilation unit for this address range. */ + struct unit *u; +}; + +/* A growable vector of compilation unit address ranges. */ + +struct unit_addrs_vector +{ + /* Memory. This is an array of struct unit_addrs. */ + struct backtrace_vector vec; + /* Number of address ranges present. */ + size_t count; +}; + +/* The information we need to map a PC to a file and line. */ + +struct dwarf_data +{ + /* The data for the next file we know about. */ + struct dwarf_data *next; + /* The base address for this file. */ + uintptr_t base_address; + /* A sorted list of address ranges. */ + struct unit_addrs *addrs; + /* Number of address ranges in list. */ + size_t addrs_count; + /* The unparsed .debug_info section. */ + const unsigned char *dwarf_info; + size_t dwarf_info_size; + /* The unparsed .debug_line section. */ + const unsigned char *dwarf_line; + size_t dwarf_line_size; + /* The unparsed .debug_ranges section. */ + const unsigned char *dwarf_ranges; + size_t dwarf_ranges_size; + /* The unparsed .debug_str section. */ + const unsigned char *dwarf_str; + size_t dwarf_str_size; + /* Whether the data is big-endian or not. */ + int is_bigendian; + /* A vector used for function addresses. We keep this here so that + we can grow the vector as we read more functions. */ + struct function_vector fvec; +}; + +/* Report an error for a DWARF buffer. */ + +static void +dwarf_buf_error (struct dwarf_buf *buf, const char *msg) +{ + char b[200]; + + snprintf (b, sizeof b, "%s in %s at %d", + msg, buf->name, (int) (buf->buf - buf->start)); + buf->error_callback (buf->data, b, 0); +} + +/* Require at least COUNT bytes in BUF. Return 1 if all is well, 0 on + error. */ + +static int +require (struct dwarf_buf *buf, size_t count) +{ + if (buf->left >= count) + return 1; + + if (!buf->reported_underflow) + { + dwarf_buf_error (buf, "DWARF underflow"); + buf->reported_underflow = 1; + } + + return 0; +} + +/* Advance COUNT bytes in BUF. Return 1 if all is well, 0 on + error. */ + +static int +advance (struct dwarf_buf *buf, size_t count) +{ + if (!require (buf, count)) + return 0; + buf->buf += count; + buf->left -= count; + return 1; +} + +/* Read one byte from BUF and advance 1 byte. */ + +static unsigned char +read_byte (struct dwarf_buf *buf) +{ + const unsigned char *p = buf->buf; + + if (!advance (buf, 1)) + return 0; + return p[0]; +} + +/* Read a signed char from BUF and advance 1 byte. */ + +static signed char +read_sbyte (struct dwarf_buf *buf) +{ + const unsigned char *p = buf->buf; + + if (!advance (buf, 1)) + return 0; + return (*p ^ 0x80) - 0x80; +} + +/* Read a uint16 from BUF and advance 2 bytes. */ + +static uint16_t +read_uint16 (struct dwarf_buf *buf) +{ + const unsigned char *p = buf->buf; + + if (!advance (buf, 2)) + return 0; + if (buf->is_bigendian) + return ((uint16_t) p[0] << 8) | (uint16_t) p[1]; + else + return ((uint16_t) p[1] << 8) | (uint16_t) p[0]; +} + +/* Read a uint32 from BUF and advance 4 bytes. */ + +static uint32_t +read_uint32 (struct dwarf_buf *buf) +{ + const unsigned char *p = buf->buf; + + if (!advance (buf, 4)) + return 0; + if (buf->is_bigendian) + return (((uint32_t) p[0] << 24) | ((uint32_t) p[1] << 16) + | ((uint32_t) p[2] << 8) | (uint32_t) p[3]); + else + return (((uint32_t) p[3] << 24) | ((uint32_t) p[2] << 16) + | ((uint32_t) p[1] << 8) | (uint32_t) p[0]); +} + +/* Read a uint64 from BUF and advance 8 bytes. */ + +static uint64_t +read_uint64 (struct dwarf_buf *buf) +{ + const unsigned char *p = buf->buf; + + if (!advance (buf, 8)) + return 0; + if (buf->is_bigendian) + return (((uint64_t) p[0] << 56) | ((uint64_t) p[1] << 48) + | ((uint64_t) p[2] << 40) | ((uint64_t) p[3] << 32) + | ((uint64_t) p[4] << 24) | ((uint64_t) p[5] << 16) + | ((uint64_t) p[6] << 8) | (uint64_t) p[7]); + else + return (((uint64_t) p[7] << 56) | ((uint64_t) p[6] << 48) + | ((uint64_t) p[5] << 40) | ((uint64_t) p[4] << 32) + | ((uint64_t) p[3] << 24) | ((uint64_t) p[2] << 16) + | ((uint64_t) p[1] << 8) | (uint64_t) p[0]); +} + +/* Read an offset from BUF and advance the appropriate number of + bytes. */ + +static uint64_t +read_offset (struct dwarf_buf *buf, int is_dwarf64) +{ + if (is_dwarf64) + return read_uint64 (buf); + else + return read_uint32 (buf); +} + +/* Read an address from BUF and advance the appropriate number of + bytes. */ + +static uint64_t +read_address (struct dwarf_buf *buf, int addrsize) +{ + switch (addrsize) + { + case 1: + return read_byte (buf); + case 2: + return read_uint16 (buf); + case 4: + return read_uint32 (buf); + case 8: + return read_uint64 (buf); + default: + dwarf_buf_error (buf, "unrecognized address size"); + return 0; + } +} + +/* Return whether a value is the highest possible address, given the + address size. */ + +static int +is_highest_address (uint64_t address, int addrsize) +{ + switch (addrsize) + { + case 1: + return address == (unsigned char) -1; + case 2: + return address == (uint16_t) -1; + case 4: + return address == (uint32_t) -1; + case 8: + return address == (uint64_t) -1; + default: + return 0; + } +} + +/* Read an unsigned LEB128 number. */ + +static uint64_t +read_uleb128 (struct dwarf_buf *buf) +{ + uint64_t ret; + unsigned int shift; + int overflow; + unsigned char b; + + ret = 0; + shift = 0; + overflow = 0; + do + { + const unsigned char *p; + + p = buf->buf; + if (!advance (buf, 1)) + return 0; + b = *p; + if (shift < 64) + ret |= ((uint64_t) (b & 0x7f)) << shift; + else if (!overflow) + { + dwarf_buf_error (buf, "LEB128 overflows uint64_t"); + overflow = 1; + } + shift += 7; + } + while ((b & 0x80) != 0); + + return ret; +} + +/* Read a signed LEB128 number. */ + +static int64_t +read_sleb128 (struct dwarf_buf *buf) +{ + uint64_t val; + unsigned int shift; + int overflow; + unsigned char b; + + val = 0; + shift = 0; + overflow = 0; + do + { + const unsigned char *p; + + p = buf->buf; + if (!advance (buf, 1)) + return 0; + b = *p; + if (shift < 64) + val |= ((uint64_t) (b & 0x7f)) << shift; + else if (!overflow) + { + dwarf_buf_error (buf, "signed LEB128 overflows uint64_t"); + overflow = 1; + } + shift += 7; + } + while ((b & 0x80) != 0); + + if ((b & 0x40) != 0 && shift < 64) + val |= ((uint64_t) -1) << shift; + + return (int64_t) val; +} + +/* Return the length of an LEB128 number. */ + +static size_t +leb128_len (const unsigned char *p) +{ + size_t ret; + + ret = 1; + while ((*p & 0x80) != 0) + { + ++p; + ++ret; + } + return ret; +} + +/* Free an abbreviations structure. */ + +static void +free_abbrevs (struct backtrace_state *state, struct abbrevs *abbrevs, + backtrace_error_callback error_callback, void *data) +{ + size_t i; + + for (i = 0; i < abbrevs->num_abbrevs; ++i) + backtrace_free (state, abbrevs->abbrevs[i].attrs, + abbrevs->abbrevs[i].num_attrs * sizeof (struct attr), + error_callback, data); + backtrace_free (state, abbrevs->abbrevs, + abbrevs->num_abbrevs * sizeof (struct abbrev), + error_callback, data); + abbrevs->num_abbrevs = 0; + abbrevs->abbrevs = NULL; +} + +/* Read an attribute value. Returns 1 on success, 0 on failure. If + the value can be represented as a uint64_t, sets *VAL and sets + *IS_VALID to 1. We don't try to store the value of other attribute + forms, because we don't care about them. */ + +static int +read_attribute (enum dwarf_form form, struct dwarf_buf *buf, + int is_dwarf64, int version, int addrsize, + const unsigned char *dwarf_str, size_t dwarf_str_size, + struct attr_val *val) +{ + /* Avoid warnings about val.u.FIELD may be used uninitialized if + this function is inlined. The warnings aren't valid but can + occur because the different fields are set and used + conditionally. */ + memset (val, 0, sizeof *val); + + switch (form) + { + case DW_FORM_addr: + val->encoding = ATTR_VAL_ADDRESS; + val->u.uint = read_address (buf, addrsize); + return 1; + case DW_FORM_block2: + val->encoding = ATTR_VAL_BLOCK; + return advance (buf, read_uint16 (buf)); + case DW_FORM_block4: + val->encoding = ATTR_VAL_BLOCK; + return advance (buf, read_uint32 (buf)); + case DW_FORM_data2: + val->encoding = ATTR_VAL_UINT; + val->u.uint = read_uint16 (buf); + return 1; + case DW_FORM_data4: + val->encoding = ATTR_VAL_UINT; + val->u.uint = read_uint32 (buf); + return 1; + case DW_FORM_data8: + val->encoding = ATTR_VAL_UINT; + val->u.uint = read_uint64 (buf); + return 1; + case DW_FORM_string: + val->encoding = ATTR_VAL_STRING; + val->u.string = (const char *) buf->buf; + return advance (buf, strnlen ((const char *) buf->buf, buf->left) + 1); + case DW_FORM_block: + val->encoding = ATTR_VAL_BLOCK; + return advance (buf, read_uleb128 (buf)); + case DW_FORM_block1: + val->encoding = ATTR_VAL_BLOCK; + return advance (buf, read_byte (buf)); + case DW_FORM_data1: + val->encoding = ATTR_VAL_UINT; + val->u.uint = read_byte (buf); + return 1; + case DW_FORM_flag: + val->encoding = ATTR_VAL_UINT; + val->u.uint = read_byte (buf); + return 1; + case DW_FORM_sdata: + val->encoding = ATTR_VAL_SINT; + val->u.sint = read_sleb128 (buf); + return 1; + case DW_FORM_strp: + { + uint64_t offset; + + offset = read_offset (buf, is_dwarf64); + if (offset >= dwarf_str_size) + { + dwarf_buf_error (buf, "DW_FORM_strp out of range"); + return 0; + } + val->encoding = ATTR_VAL_STRING; + val->u.string = (const char *) dwarf_str + offset; + return 1; + } + case DW_FORM_udata: + val->encoding = ATTR_VAL_UINT; + val->u.uint = read_uleb128 (buf); + return 1; + case DW_FORM_ref_addr: + val->encoding = ATTR_VAL_REF_INFO; + if (version == 2) + val->u.uint = read_address (buf, addrsize); + else + val->u.uint = read_offset (buf, is_dwarf64); + return 1; + case DW_FORM_ref1: + val->encoding = ATTR_VAL_REF_UNIT; + val->u.uint = read_byte (buf); + return 1; + case DW_FORM_ref2: + val->encoding = ATTR_VAL_REF_UNIT; + val->u.uint = read_uint16 (buf); + return 1; + case DW_FORM_ref4: + val->encoding = ATTR_VAL_REF_UNIT; + val->u.uint = read_uint32 (buf); + return 1; + case DW_FORM_ref8: + val->encoding = ATTR_VAL_REF_UNIT; + val->u.uint = read_uint64 (buf); + return 1; + case DW_FORM_ref_udata: + val->encoding = ATTR_VAL_REF_UNIT; + val->u.uint = read_uleb128 (buf); + return 1; + case DW_FORM_indirect: + { + uint64_t form; + + form = read_uleb128 (buf); + return read_attribute ((enum dwarf_form) form, buf, is_dwarf64, + version, addrsize, dwarf_str, dwarf_str_size, + val); + } + case DW_FORM_sec_offset: + val->encoding = ATTR_VAL_REF_SECTION; + val->u.uint = read_offset (buf, is_dwarf64); + return 1; + case DW_FORM_exprloc: + val->encoding = ATTR_VAL_EXPR; + return advance (buf, read_uleb128 (buf)); + case DW_FORM_flag_present: + val->encoding = ATTR_VAL_UINT; + val->u.uint = 1; + return 1; + case DW_FORM_ref_sig8: + val->encoding = ATTR_VAL_REF_TYPE; + val->u.uint = read_uint64 (buf); + return 1; + case DW_FORM_GNU_addr_index: + val->encoding = ATTR_VAL_REF_SECTION; + val->u.uint = read_uleb128 (buf); + return 1; + case DW_FORM_GNU_str_index: + val->encoding = ATTR_VAL_REF_SECTION; + val->u.uint = read_uleb128 (buf); + return 1; + case DW_FORM_GNU_ref_alt: + val->encoding = ATTR_VAL_REF_SECTION; + val->u.uint = read_offset (buf, is_dwarf64); + return 1; + case DW_FORM_GNU_strp_alt: + val->encoding = ATTR_VAL_REF_SECTION; + val->u.uint = read_offset (buf, is_dwarf64); + return 1; + default: + dwarf_buf_error (buf, "unrecognized DWARF form"); + return 0; + } +} + +/* Compare function_addrs for qsort. When ranges are nested, make the + smallest one sort last. */ + +static int +function_addrs_compare (const void *v1, const void *v2) +{ + const struct function_addrs *a1 = (const struct function_addrs *) v1; + const struct function_addrs *a2 = (const struct function_addrs *) v2; + + if (a1->low < a2->low) + return -1; + if (a1->low > a2->low) + return 1; + if (a1->high < a2->high) + return 1; + if (a1->high > a2->high) + return -1; + return strcmp (a1->function->name, a2->function->name); +} + +/* Compare a PC against a function_addrs for bsearch. Note that if + there are multiple ranges containing PC, which one will be returned + is unpredictable. We compensate for that in dwarf_fileline. */ + +static int +function_addrs_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct function_addrs *entry = (const struct function_addrs *) ventry; + uintptr_t pc; + + pc = *key; + if (pc < entry->low) + return -1; + else if (pc >= entry->high) + return 1; + else + return 0; +} + +/* Add a new compilation unit address range to a vector. Returns 1 on + success, 0 on failure. */ + +static int +add_unit_addr (struct backtrace_state *state, uintptr_t base_address, + struct unit_addrs addrs, + backtrace_error_callback error_callback, void *data, + struct unit_addrs_vector *vec) +{ + struct unit_addrs *p; + + /* Add in the base address of the module here, so that we can look + up the PC directly. */ + addrs.low += base_address; + addrs.high += base_address; + + /* Try to merge with the last entry. */ + if (vec->count > 0) + { + p = (struct unit_addrs *) vec->vec.base + (vec->count - 1); + if ((addrs.low == p->high || addrs.low == p->high + 1) + && addrs.u == p->u) + { + if (addrs.high > p->high) + p->high = addrs.high; + return 1; + } + } + + p = ((struct unit_addrs *) + backtrace_vector_grow (state, sizeof (struct unit_addrs), + error_callback, data, &vec->vec)); + if (p == NULL) + return 0; + + *p = addrs; + ++vec->count; + return 1; +} + +/* Free a unit address vector. */ + +static void +free_unit_addrs_vector (struct backtrace_state *state, + struct unit_addrs_vector *vec, + backtrace_error_callback error_callback, void *data) +{ + struct unit_addrs *addrs; + size_t i; + + addrs = (struct unit_addrs *) vec->vec.base; + for (i = 0; i < vec->count; ++i) + free_abbrevs (state, &addrs[i].u->abbrevs, error_callback, data); +} + +/* Compare unit_addrs for qsort. When ranges are nested, make the + smallest one sort last. */ + +static int +unit_addrs_compare (const void *v1, const void *v2) +{ + const struct unit_addrs *a1 = (const struct unit_addrs *) v1; + const struct unit_addrs *a2 = (const struct unit_addrs *) v2; + + if (a1->low < a2->low) + return -1; + if (a1->low > a2->low) + return 1; + if (a1->high < a2->high) + return 1; + if (a1->high > a2->high) + return -1; + if (a1->u->lineoff < a2->u->lineoff) + return -1; + if (a1->u->lineoff > a2->u->lineoff) + return 1; + return 0; +} + +/* Compare a PC against a unit_addrs for bsearch. Note that if there + are multiple ranges containing PC, which one will be returned is + unpredictable. We compensate for that in dwarf_fileline. */ + +static int +unit_addrs_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct unit_addrs *entry = (const struct unit_addrs *) ventry; + uintptr_t pc; + + pc = *key; + if (pc < entry->low) + return -1; + else if (pc >= entry->high) + return 1; + else + return 0; +} + +/* Sort the line vector by PC. We want a stable sort here to maintain + the order of lines for the same PC values. Since the sequence is + being sorted in place, their addresses cannot be relied on to + maintain stability. That is the purpose of the index member. */ + +static int +line_compare (const void *v1, const void *v2) +{ + const struct line *ln1 = (const struct line *) v1; + const struct line *ln2 = (const struct line *) v2; + + if (ln1->pc < ln2->pc) + return -1; + else if (ln1->pc > ln2->pc) + return 1; + else if (ln1->idx < ln2->idx) + return -1; + else if (ln1->idx > ln2->idx) + return 1; + else + return 0; +} + +/* Find a PC in a line vector. We always allocate an extra entry at + the end of the lines vector, so that this routine can safely look + at the next entry. Note that when there are multiple mappings for + the same PC value, this will return the last one. */ + +static int +line_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct line *entry = (const struct line *) ventry; + uintptr_t pc; + + pc = *key; + if (pc < entry->pc) + return -1; + else if (pc >= (entry + 1)->pc) + return 1; + else + return 0; +} + +/* Sort the abbrevs by the abbrev code. This function is passed to + both qsort and bsearch. */ + +static int +abbrev_compare (const void *v1, const void *v2) +{ + const struct abbrev *a1 = (const struct abbrev *) v1; + const struct abbrev *a2 = (const struct abbrev *) v2; + + if (a1->code < a2->code) + return -1; + else if (a1->code > a2->code) + return 1; + else + { + /* This really shouldn't happen. It means there are two + different abbrevs with the same code, and that means we don't + know which one lookup_abbrev should return. */ + return 0; + } +} + +/* Read the abbreviation table for a compilation unit. Returns 1 on + success, 0 on failure. */ + +static int +read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset, + const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size, + int is_bigendian, backtrace_error_callback error_callback, + void *data, struct abbrevs *abbrevs) +{ + struct dwarf_buf abbrev_buf; + struct dwarf_buf count_buf; + size_t num_abbrevs; + + abbrevs->num_abbrevs = 0; + abbrevs->abbrevs = NULL; + + if (abbrev_offset >= dwarf_abbrev_size) + { + error_callback (data, "abbrev offset out of range", 0); + return 0; + } + + abbrev_buf.name = ".debug_abbrev"; + abbrev_buf.start = dwarf_abbrev; + abbrev_buf.buf = dwarf_abbrev + abbrev_offset; + abbrev_buf.left = dwarf_abbrev_size - abbrev_offset; + abbrev_buf.is_bigendian = is_bigendian; + abbrev_buf.error_callback = error_callback; + abbrev_buf.data = data; + abbrev_buf.reported_underflow = 0; + + /* Count the number of abbrevs in this list. */ + + count_buf = abbrev_buf; + num_abbrevs = 0; + while (read_uleb128 (&count_buf) != 0) + { + if (count_buf.reported_underflow) + return 0; + ++num_abbrevs; + // Skip tag. + read_uleb128 (&count_buf); + // Skip has_children. + read_byte (&count_buf); + // Skip attributes. + while (read_uleb128 (&count_buf) != 0) + read_uleb128 (&count_buf); + // Skip form of last attribute. + read_uleb128 (&count_buf); + } + + if (count_buf.reported_underflow) + return 0; + + if (num_abbrevs == 0) + return 1; + + abbrevs->num_abbrevs = num_abbrevs; + abbrevs->abbrevs = ((struct abbrev *) + backtrace_alloc (state, + num_abbrevs * sizeof (struct abbrev), + error_callback, data)); + if (abbrevs->abbrevs == NULL) + return 0; + memset (abbrevs->abbrevs, 0, num_abbrevs * sizeof (struct abbrev)); + + num_abbrevs = 0; + while (1) + { + uint64_t code; + struct abbrev a; + size_t num_attrs; + struct attr *attrs; + + if (abbrev_buf.reported_underflow) + goto fail; + + code = read_uleb128 (&abbrev_buf); + if (code == 0) + break; + + a.code = code; + a.tag = (enum dwarf_tag) read_uleb128 (&abbrev_buf); + a.has_children = read_byte (&abbrev_buf); + + count_buf = abbrev_buf; + num_attrs = 0; + while (read_uleb128 (&count_buf) != 0) + { + ++num_attrs; + read_uleb128 (&count_buf); + } + + if (num_attrs == 0) + { + attrs = NULL; + read_uleb128 (&abbrev_buf); + read_uleb128 (&abbrev_buf); + } + else + { + attrs = ((struct attr *) + backtrace_alloc (state, num_attrs * sizeof *attrs, + error_callback, data)); + if (attrs == NULL) + goto fail; + num_attrs = 0; + while (1) + { + uint64_t name; + uint64_t form; + + name = read_uleb128 (&abbrev_buf); + form = read_uleb128 (&abbrev_buf); + if (name == 0) + break; + attrs[num_attrs].name = (enum dwarf_attribute) name; + attrs[num_attrs].form = (enum dwarf_form) form; + ++num_attrs; + } + } + + a.num_attrs = num_attrs; + a.attrs = attrs; + + abbrevs->abbrevs[num_abbrevs] = a; + ++num_abbrevs; + } + + backtrace_qsort (abbrevs->abbrevs, abbrevs->num_abbrevs, + sizeof (struct abbrev), abbrev_compare); + + return 1; + + fail: + free_abbrevs (state, abbrevs, error_callback, data); + return 0; +} + +/* Return the abbrev information for an abbrev code. */ + +static const struct abbrev * +lookup_abbrev (struct abbrevs *abbrevs, uint64_t code, + backtrace_error_callback error_callback, void *data) +{ + struct abbrev key; + void *p; + + /* With GCC, where abbrevs are simply numbered in order, we should + be able to just look up the entry. */ + if (code - 1 < abbrevs->num_abbrevs + && abbrevs->abbrevs[code - 1].code == code) + return &abbrevs->abbrevs[code - 1]; + + /* Otherwise we have to search. */ + memset (&key, 0, sizeof key); + key.code = code; + p = bsearch (&key, abbrevs->abbrevs, abbrevs->num_abbrevs, + sizeof (struct abbrev), abbrev_compare); + if (p == NULL) + { + error_callback (data, "invalid abbreviation code", 0); + return NULL; + } + return (const struct abbrev *) p; +} + +/* Add non-contiguous address ranges for a compilation unit. Returns + 1 on success, 0 on failure. */ + +static int +add_unit_ranges (struct backtrace_state *state, uintptr_t base_address, + struct unit *u, uint64_t ranges, uint64_t base, + int is_bigendian, const unsigned char *dwarf_ranges, + size_t dwarf_ranges_size, + backtrace_error_callback error_callback, void *data, + struct unit_addrs_vector *addrs) +{ + struct dwarf_buf ranges_buf; + + if (ranges >= dwarf_ranges_size) + { + error_callback (data, "ranges offset out of range", 0); + return 0; + } + + ranges_buf.name = ".debug_ranges"; + ranges_buf.start = dwarf_ranges; + ranges_buf.buf = dwarf_ranges + ranges; + ranges_buf.left = dwarf_ranges_size - ranges; + ranges_buf.is_bigendian = is_bigendian; + ranges_buf.error_callback = error_callback; + ranges_buf.data = data; + ranges_buf.reported_underflow = 0; + + while (1) + { + uint64_t low; + uint64_t high; + + if (ranges_buf.reported_underflow) + return 0; + + low = read_address (&ranges_buf, u->addrsize); + high = read_address (&ranges_buf, u->addrsize); + + if (low == 0 && high == 0) + break; + + if (is_highest_address (low, u->addrsize)) + base = high; + else + { + struct unit_addrs a; + + a.low = low + base; + a.high = high + base; + a.u = u; + if (!add_unit_addr (state, base_address, a, error_callback, data, + addrs)) + return 0; + } + } + + if (ranges_buf.reported_underflow) + return 0; + + return 1; +} + +/* Find the address range covered by a compilation unit, reading from + UNIT_BUF and adding values to U. Returns 1 if all data could be + read, 0 if there is some error. */ + +static int +find_address_ranges (struct backtrace_state *state, uintptr_t base_address, + struct dwarf_buf *unit_buf, + const unsigned char *dwarf_str, size_t dwarf_str_size, + const unsigned char *dwarf_ranges, + size_t dwarf_ranges_size, + int is_bigendian, backtrace_error_callback error_callback, + void *data, struct unit *u, + struct unit_addrs_vector *addrs) +{ + while (unit_buf->left > 0) + { + uint64_t code; + const struct abbrev *abbrev; + uint64_t lowpc; + int have_lowpc; + uint64_t highpc; + int have_highpc; + int highpc_is_relative; + uint64_t ranges; + int have_ranges; + size_t i; + + code = read_uleb128 (unit_buf); + if (code == 0) + return 1; + + abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); + if (abbrev == NULL) + return 0; + + lowpc = 0; + have_lowpc = 0; + highpc = 0; + have_highpc = 0; + highpc_is_relative = 0; + ranges = 0; + have_ranges = 0; + for (i = 0; i < abbrev->num_attrs; ++i) + { + struct attr_val val; + + if (!read_attribute (abbrev->attrs[i].form, unit_buf, + u->is_dwarf64, u->version, u->addrsize, + dwarf_str, dwarf_str_size, &val)) + return 0; + + switch (abbrev->attrs[i].name) + { + case DW_AT_low_pc: + if (val.encoding == ATTR_VAL_ADDRESS) + { + lowpc = val.u.uint; + have_lowpc = 1; + } + break; + + case DW_AT_high_pc: + if (val.encoding == ATTR_VAL_ADDRESS) + { + highpc = val.u.uint; + have_highpc = 1; + } + else if (val.encoding == ATTR_VAL_UINT) + { + highpc = val.u.uint; + have_highpc = 1; + highpc_is_relative = 1; + } + break; + + case DW_AT_ranges: + if (val.encoding == ATTR_VAL_UINT + || val.encoding == ATTR_VAL_REF_SECTION) + { + ranges = val.u.uint; + have_ranges = 1; + } + break; + + case DW_AT_stmt_list: + if (abbrev->tag == DW_TAG_compile_unit + && (val.encoding == ATTR_VAL_UINT + || val.encoding == ATTR_VAL_REF_SECTION)) + u->lineoff = val.u.uint; + break; + + case DW_AT_name: + if (abbrev->tag == DW_TAG_compile_unit + && val.encoding == ATTR_VAL_STRING) + u->filename = val.u.string; + break; + + case DW_AT_comp_dir: + if (abbrev->tag == DW_TAG_compile_unit + && val.encoding == ATTR_VAL_STRING) + u->comp_dir = val.u.string; + break; + + default: + break; + } + } + + if (abbrev->tag == DW_TAG_compile_unit + || abbrev->tag == DW_TAG_subprogram) + { + if (have_ranges) + { + if (!add_unit_ranges (state, base_address, u, ranges, lowpc, + is_bigendian, dwarf_ranges, + dwarf_ranges_size, error_callback, + data, addrs)) + return 0; + } + else if (have_lowpc && have_highpc) + { + struct unit_addrs a; + + if (highpc_is_relative) + highpc += lowpc; + a.low = lowpc; + a.high = highpc; + a.u = u; + + if (!add_unit_addr (state, base_address, a, error_callback, data, + addrs)) + return 0; + } + + /* If we found the PC range in the DW_TAG_compile_unit, we + can stop now. */ + if (abbrev->tag == DW_TAG_compile_unit + && (have_ranges || (have_lowpc && have_highpc))) + return 1; + } + + if (abbrev->has_children) + { + if (!find_address_ranges (state, base_address, unit_buf, + dwarf_str, dwarf_str_size, + dwarf_ranges, dwarf_ranges_size, + is_bigendian, error_callback, data, + u, addrs)) + return 0; + } + } + + return 1; +} + +/* Build a mapping from address ranges to the compilation units where + the line number information for that range can be found. Returns 1 + on success, 0 on failure. */ + +static int +build_address_map (struct backtrace_state *state, uintptr_t base_address, + const unsigned char *dwarf_info, size_t dwarf_info_size, + const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size, + const unsigned char *dwarf_ranges, size_t dwarf_ranges_size, + const unsigned char *dwarf_str, size_t dwarf_str_size, + int is_bigendian, backtrace_error_callback error_callback, + void *data, struct unit_addrs_vector *addrs) +{ + struct dwarf_buf info; + struct abbrevs abbrevs; + + memset (&addrs->vec, 0, sizeof addrs->vec); + addrs->count = 0; + + /* Read through the .debug_info section. FIXME: Should we use the + .debug_aranges section? gdb and addr2line don't use it, but I'm + not sure why. */ + + info.name = ".debug_info"; + info.start = dwarf_info; + info.buf = dwarf_info; + info.left = dwarf_info_size; + info.is_bigendian = is_bigendian; + info.error_callback = error_callback; + info.data = data; + info.reported_underflow = 0; + + memset (&abbrevs, 0, sizeof abbrevs); + while (info.left > 0) + { + const unsigned char *unit_data_start; + uint64_t len; + int is_dwarf64; + struct dwarf_buf unit_buf; + int version; + uint64_t abbrev_offset; + int addrsize; + struct unit *u; + + if (info.reported_underflow) + goto fail; + + unit_data_start = info.buf; + + is_dwarf64 = 0; + len = read_uint32 (&info); + if (len == 0xffffffff) + { + len = read_uint64 (&info); + is_dwarf64 = 1; + } + + unit_buf = info; + unit_buf.left = len; + + if (!advance (&info, len)) + goto fail; + + version = read_uint16 (&unit_buf); + if (version < 2 || version > 4) + { + dwarf_buf_error (&unit_buf, "unrecognized DWARF version"); + goto fail; + } + + abbrev_offset = read_offset (&unit_buf, is_dwarf64); + if (!read_abbrevs (state, abbrev_offset, dwarf_abbrev, dwarf_abbrev_size, + is_bigendian, error_callback, data, &abbrevs)) + goto fail; + + addrsize = read_byte (&unit_buf); + + u = ((struct unit *) + backtrace_alloc (state, sizeof *u, error_callback, data)); + if (u == NULL) + goto fail; + u->unit_data = unit_buf.buf; + u->unit_data_len = unit_buf.left; + u->unit_data_offset = unit_buf.buf - unit_data_start; + u->version = version; + u->is_dwarf64 = is_dwarf64; + u->addrsize = addrsize; + u->filename = NULL; + u->comp_dir = NULL; + u->abs_filename = NULL; + u->lineoff = 0; + u->abbrevs = abbrevs; + memset (&abbrevs, 0, sizeof abbrevs); + + /* The actual line number mappings will be read as needed. */ + u->lines = NULL; + u->lines_count = 0; + u->function_addrs = NULL; + u->function_addrs_count = 0; + + if (!find_address_ranges (state, base_address, &unit_buf, + dwarf_str, dwarf_str_size, + dwarf_ranges, dwarf_ranges_size, + is_bigendian, error_callback, data, + u, addrs)) + { + free_abbrevs (state, &u->abbrevs, error_callback, data); + backtrace_free (state, u, sizeof *u, error_callback, data); + goto fail; + } + + if (unit_buf.reported_underflow) + { + free_abbrevs (state, &u->abbrevs, error_callback, data); + backtrace_free (state, u, sizeof *u, error_callback, data); + goto fail; + } + } + if (info.reported_underflow) + goto fail; + + return 1; + + fail: + free_abbrevs (state, &abbrevs, error_callback, data); + free_unit_addrs_vector (state, addrs, error_callback, data); + return 0; +} + +/* Add a new mapping to the vector of line mappings that we are + building. Returns 1 on success, 0 on failure. */ + +static int +add_line (struct backtrace_state *state, struct dwarf_data *ddata, + uintptr_t pc, const char *filename, int lineno, + backtrace_error_callback error_callback, void *data, + struct line_vector *vec) +{ + struct line *ln; + + /* If we are adding the same mapping, ignore it. This can happen + when using discriminators. */ + if (vec->count > 0) + { + ln = (struct line *) vec->vec.base + (vec->count - 1); + if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno) + return 1; + } + + ln = ((struct line *) + backtrace_vector_grow (state, sizeof (struct line), error_callback, + data, &vec->vec)); + if (ln == NULL) + return 0; + + /* Add in the base address here, so that we can look up the PC + directly. */ + ln->pc = pc + ddata->base_address; + + ln->filename = filename; + ln->lineno = lineno; + ln->idx = vec->count; + + ++vec->count; + + return 1; +} + +/* Free the line header information. If FREE_FILENAMES is true we + free the file names themselves, otherwise we leave them, as there + may be line structures pointing to them. */ + +static void +free_line_header (struct backtrace_state *state, struct line_header *hdr, + backtrace_error_callback error_callback, void *data) +{ + backtrace_free (state, hdr->dirs, hdr->dirs_count * sizeof (const char *), + error_callback, data); + backtrace_free (state, hdr->filenames, + hdr->filenames_count * sizeof (char *), + error_callback, data); +} + +/* Read the line header. Return 1 on success, 0 on failure. */ + +static int +read_line_header (struct backtrace_state *state, struct unit *u, + int is_dwarf64, struct dwarf_buf *line_buf, + struct line_header *hdr) +{ + uint64_t hdrlen; + struct dwarf_buf hdr_buf; + const unsigned char *p; + const unsigned char *pend; + size_t i; + + hdr->version = read_uint16 (line_buf); + if (hdr->version < 2 || hdr->version > 4) + { + dwarf_buf_error (line_buf, "unsupported line number version"); + return 0; + } + + hdrlen = read_offset (line_buf, is_dwarf64); + + hdr_buf = *line_buf; + hdr_buf.left = hdrlen; + + if (!advance (line_buf, hdrlen)) + return 0; + + hdr->min_insn_len = read_byte (&hdr_buf); + if (hdr->version < 4) + hdr->max_ops_per_insn = 1; + else + hdr->max_ops_per_insn = read_byte (&hdr_buf); + + /* We don't care about default_is_stmt. */ + read_byte (&hdr_buf); + + hdr->line_base = read_sbyte (&hdr_buf); + hdr->line_range = read_byte (&hdr_buf); + + hdr->opcode_base = read_byte (&hdr_buf); + hdr->opcode_lengths = hdr_buf.buf; + if (!advance (&hdr_buf, hdr->opcode_base - 1)) + return 0; + + /* Count the number of directory entries. */ + hdr->dirs_count = 0; + p = hdr_buf.buf; + pend = p + hdr_buf.left; + while (p < pend && *p != '\0') + { + p += strnlen((const char *) p, pend - p) + 1; + ++hdr->dirs_count; + } + + hdr->dirs = ((const char **) + backtrace_alloc (state, + hdr->dirs_count * sizeof (const char *), + line_buf->error_callback, line_buf->data)); + if (hdr->dirs == NULL) + return 0; + + i = 0; + while (*hdr_buf.buf != '\0') + { + if (hdr_buf.reported_underflow) + return 0; + + hdr->dirs[i] = (const char *) hdr_buf.buf; + ++i; + if (!advance (&hdr_buf, + strnlen ((const char *) hdr_buf.buf, hdr_buf.left) + 1)) + return 0; + } + if (!advance (&hdr_buf, 1)) + return 0; + + /* Count the number of file entries. */ + hdr->filenames_count = 0; + p = hdr_buf.buf; + pend = p + hdr_buf.left; + while (p < pend && *p != '\0') + { + p += strnlen ((const char *) p, pend - p) + 1; + p += leb128_len (p); + p += leb128_len (p); + p += leb128_len (p); + ++hdr->filenames_count; + } + + hdr->filenames = ((const char **) + backtrace_alloc (state, + hdr->filenames_count * sizeof (char *), + line_buf->error_callback, + line_buf->data)); + if (hdr->filenames == NULL) + return 0; + i = 0; + while (*hdr_buf.buf != '\0') + { + const char *filename; + uint64_t dir_index; + + if (hdr_buf.reported_underflow) + return 0; + + filename = (const char *) hdr_buf.buf; + if (!advance (&hdr_buf, + strnlen ((const char *) hdr_buf.buf, hdr_buf.left) + 1)) + return 0; + dir_index = read_uleb128 (&hdr_buf); + if (IS_ABSOLUTE_PATH (filename) + || (dir_index == 0 && u->comp_dir == NULL)) + hdr->filenames[i] = filename; + else + { + const char *dir; + size_t dir_len; + size_t filename_len; + char *s; + + if (dir_index == 0) + dir = u->comp_dir; + else if (dir_index - 1 < hdr->dirs_count) + dir = hdr->dirs[dir_index - 1]; + else + { + dwarf_buf_error (line_buf, + ("invalid directory index in " + "line number program header")); + return 0; + } + dir_len = strlen (dir); + filename_len = strlen (filename); + s = ((char *) + backtrace_alloc (state, dir_len + filename_len + 2, + line_buf->error_callback, line_buf->data)); + if (s == NULL) + return 0; + memcpy (s, dir, dir_len); + /* FIXME: If we are on a DOS-based file system, and the + directory or the file name use backslashes, then we + should use a backslash here. */ + s[dir_len] = '/'; + memcpy (s + dir_len + 1, filename, filename_len + 1); + hdr->filenames[i] = s; + } + + /* Ignore the modification time and size. */ + read_uleb128 (&hdr_buf); + read_uleb128 (&hdr_buf); + + ++i; + } + + if (hdr_buf.reported_underflow) + return 0; + + return 1; +} + +/* Read the line program, adding line mappings to VEC. Return 1 on + success, 0 on failure. */ + +static int +read_line_program (struct backtrace_state *state, struct dwarf_data *ddata, + struct unit *u, const struct line_header *hdr, + struct dwarf_buf *line_buf, struct line_vector *vec) +{ + uint64_t address; + unsigned int op_index; + const char *reset_filename; + const char *filename; + int lineno; + + address = 0; + op_index = 0; + if (hdr->filenames_count > 0) + reset_filename = hdr->filenames[0]; + else + reset_filename = ""; + filename = reset_filename; + lineno = 1; + while (line_buf->left > 0) + { + unsigned int op; + + op = read_byte (line_buf); + if (op >= hdr->opcode_base) + { + unsigned int advance; + + /* Special opcode. */ + op -= hdr->opcode_base; + advance = op / hdr->line_range; + address += (hdr->min_insn_len * (op_index + advance) + / hdr->max_ops_per_insn); + op_index = (op_index + advance) % hdr->max_ops_per_insn; + lineno += hdr->line_base + (int) (op % hdr->line_range); + add_line (state, ddata, address, filename, lineno, + line_buf->error_callback, line_buf->data, vec); + } + else if (op == DW_LNS_extended_op) + { + uint64_t len; + + len = read_uleb128 (line_buf); + op = read_byte (line_buf); + switch (op) + { + case DW_LNE_end_sequence: + /* FIXME: Should we mark the high PC here? It seems + that we already have that information from the + compilation unit. */ + address = 0; + op_index = 0; + filename = reset_filename; + lineno = 1; + break; + case DW_LNE_set_address: + address = read_address (line_buf, u->addrsize); + break; + case DW_LNE_define_file: + { + const char *f; + unsigned int dir_index; + + f = (const char *) line_buf->buf; + if (!advance (line_buf, strnlen (f, line_buf->left) + 1)) + return 0; + dir_index = read_uleb128 (line_buf); + /* Ignore that time and length. */ + read_uleb128 (line_buf); + read_uleb128 (line_buf); + if (IS_ABSOLUTE_PATH (f)) + filename = f; + else + { + const char *dir; + size_t dir_len; + size_t f_len; + char *p; + + if (dir_index == 0) + dir = u->comp_dir; + else if (dir_index - 1 < hdr->dirs_count) + dir = hdr->dirs[dir_index - 1]; + else + { + dwarf_buf_error (line_buf, + ("invalid directory index " + "in line number program")); + return 0; + } + dir_len = strlen (dir); + f_len = strlen (f); + p = ((char *) + backtrace_alloc (state, dir_len + f_len + 2, + line_buf->error_callback, + line_buf->data)); + if (p == NULL) + return 0; + memcpy (p, dir, dir_len); + /* FIXME: If we are on a DOS-based file system, + and the directory or the file name use + backslashes, then we should use a backslash + here. */ + p[dir_len] = '/'; + memcpy (p + dir_len + 1, f, f_len + 1); + filename = p; + } + } + break; + case DW_LNE_set_discriminator: + /* We don't care about discriminators. */ + read_uleb128 (line_buf); + break; + default: + if (!advance (line_buf, len - 1)) + return 0; + break; + } + } + else + { + switch (op) + { + case DW_LNS_copy: + add_line (state, ddata, address, filename, lineno, + line_buf->error_callback, line_buf->data, vec); + break; + case DW_LNS_advance_pc: + { + uint64_t advance; + + advance = read_uleb128 (line_buf); + address += (hdr->min_insn_len * (op_index + advance) + / hdr->max_ops_per_insn); + op_index = (op_index + advance) % hdr->max_ops_per_insn; + } + break; + case DW_LNS_advance_line: + lineno += (int) read_sleb128 (line_buf); + break; + case DW_LNS_set_file: + { + uint64_t fileno; + + fileno = read_uleb128 (line_buf); + if (fileno == 0) + filename = ""; + else + { + if (fileno - 1 >= hdr->filenames_count) + { + dwarf_buf_error (line_buf, + ("invalid file number in " + "line number program")); + return 0; + } + filename = hdr->filenames[fileno - 1]; + } + } + break; + case DW_LNS_set_column: + read_uleb128 (line_buf); + break; + case DW_LNS_negate_stmt: + break; + case DW_LNS_set_basic_block: + break; + case DW_LNS_const_add_pc: + { + unsigned int advance; + + op = 255 - hdr->opcode_base; + advance = op / hdr->line_range; + address += (hdr->min_insn_len * (op_index + advance) + / hdr->max_ops_per_insn); + op_index = (op_index + advance) % hdr->max_ops_per_insn; + } + break; + case DW_LNS_fixed_advance_pc: + address += read_uint16 (line_buf); + op_index = 0; + break; + case DW_LNS_set_prologue_end: + break; + case DW_LNS_set_epilogue_begin: + break; + case DW_LNS_set_isa: + read_uleb128 (line_buf); + break; + default: + { + unsigned int i; + + for (i = hdr->opcode_lengths[op - 1]; i > 0; --i) + read_uleb128 (line_buf); + } + break; + } + } + } + + return 1; +} + +/* Read the line number information for a compilation unit. Returns 1 + on success, 0 on failure. */ + +static int +read_line_info (struct backtrace_state *state, struct dwarf_data *ddata, + backtrace_error_callback error_callback, void *data, + struct unit *u, struct line_header *hdr, struct line **lines, + size_t *lines_count) +{ + struct line_vector vec; + struct dwarf_buf line_buf; + uint64_t len; + int is_dwarf64; + struct line *ln; + + memset (&vec.vec, 0, sizeof vec.vec); + vec.count = 0; + + memset (hdr, 0, sizeof *hdr); + + if (u->lineoff != (off_t) (size_t) u->lineoff + || (size_t) u->lineoff >= ddata->dwarf_line_size) + { + error_callback (data, "unit line offset out of range", 0); + goto fail; + } + + line_buf.name = ".debug_line"; + line_buf.start = ddata->dwarf_line; + line_buf.buf = ddata->dwarf_line + u->lineoff; + line_buf.left = ddata->dwarf_line_size - u->lineoff; + line_buf.is_bigendian = ddata->is_bigendian; + line_buf.error_callback = error_callback; + line_buf.data = data; + line_buf.reported_underflow = 0; + + is_dwarf64 = 0; + len = read_uint32 (&line_buf); + if (len == 0xffffffff) + { + len = read_uint64 (&line_buf); + is_dwarf64 = 1; + } + line_buf.left = len; + + if (!read_line_header (state, u, is_dwarf64, &line_buf, hdr)) + goto fail; + + if (!read_line_program (state, ddata, u, hdr, &line_buf, &vec)) + goto fail; + + if (line_buf.reported_underflow) + goto fail; + + if (vec.count == 0) + { + /* This is not a failure in the sense of a generating an error, + but it is a failure in that sense that we have no useful + information. */ + goto fail; + } + + /* Allocate one extra entry at the end. */ + ln = ((struct line *) + backtrace_vector_grow (state, sizeof (struct line), error_callback, + data, &vec.vec)); + if (ln == NULL) + goto fail; + ln->pc = (uintptr_t) -1; + ln->filename = NULL; + ln->lineno = 0; + ln->idx = 0; + + if (!backtrace_vector_release (state, &vec.vec, error_callback, data)) + goto fail; + + ln = (struct line *) vec.vec.base; + backtrace_qsort (ln, vec.count, sizeof (struct line), line_compare); + + *lines = ln; + *lines_count = vec.count; + + return 1; + + fail: + vec.vec.alc += vec.vec.size; + vec.vec.size = 0; + backtrace_vector_release (state, &vec.vec, error_callback, data); + free_line_header (state, hdr, error_callback, data); + *lines = (struct line *) (uintptr_t) -1; + *lines_count = 0; + return 0; +} + +/* Read the name of a function from a DIE referenced by a + DW_AT_abstract_origin or DW_AT_specification tag. OFFSET is within + the same compilation unit. */ + +static const char * +read_referenced_name (struct dwarf_data *ddata, struct unit *u, + uint64_t offset, backtrace_error_callback error_callback, + void *data) +{ + struct dwarf_buf unit_buf; + uint64_t code; + const struct abbrev *abbrev; + const char *ret; + size_t i; + + /* OFFSET is from the start of the data for this compilation unit. + U->unit_data is the data, but it starts U->unit_data_offset bytes + from the beginning. */ + + if (offset < u->unit_data_offset + || offset - u->unit_data_offset >= u->unit_data_len) + { + error_callback (data, + "abstract origin or specification out of range", + 0); + return NULL; + } + + offset -= u->unit_data_offset; + + unit_buf.name = ".debug_info"; + unit_buf.start = ddata->dwarf_info; + unit_buf.buf = u->unit_data + offset; + unit_buf.left = u->unit_data_len - offset; + unit_buf.is_bigendian = ddata->is_bigendian; + unit_buf.error_callback = error_callback; + unit_buf.data = data; + unit_buf.reported_underflow = 0; + + code = read_uleb128 (&unit_buf); + if (code == 0) + { + dwarf_buf_error (&unit_buf, "invalid abstract origin or specification"); + return NULL; + } + + abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); + if (abbrev == NULL) + return NULL; + + ret = NULL; + for (i = 0; i < abbrev->num_attrs; ++i) + { + struct attr_val val; + + if (!read_attribute (abbrev->attrs[i].form, &unit_buf, + u->is_dwarf64, u->version, u->addrsize, + ddata->dwarf_str, ddata->dwarf_str_size, + &val)) + return NULL; + + switch (abbrev->attrs[i].name) + { + case DW_AT_name: + /* We prefer the linkage name if get one. */ + if (val.encoding == ATTR_VAL_STRING) + ret = val.u.string; + break; + + case DW_AT_linkage_name: + case DW_AT_MIPS_linkage_name: + if (val.encoding == ATTR_VAL_STRING) + return val.u.string; + break; + + case DW_AT_specification: + if (abbrev->attrs[i].form == DW_FORM_ref_addr + || abbrev->attrs[i].form == DW_FORM_ref_sig8) + { + /* This refers to a specification defined in some other + compilation unit. We can handle this case if we + must, but it's harder. */ + break; + } + if (val.encoding == ATTR_VAL_UINT + || val.encoding == ATTR_VAL_REF_UNIT) + { + const char *name; + + name = read_referenced_name (ddata, u, val.u.uint, + error_callback, data); + if (name != NULL) + ret = name; + } + break; + + default: + break; + } + } + + return ret; +} + +/* Add a single range to U that maps to function. Returns 1 on + success, 0 on error. */ + +static int +add_function_range (struct backtrace_state *state, struct dwarf_data *ddata, + struct function *function, uint64_t lowpc, uint64_t highpc, + backtrace_error_callback error_callback, + void *data, struct function_vector *vec) +{ + struct function_addrs *p; + + /* Add in the base address here, so that we can look up the PC + directly. */ + lowpc += ddata->base_address; + highpc += ddata->base_address; + + if (vec->count > 0) + { + p = (struct function_addrs *) vec->vec.base + vec->count - 1; + if ((lowpc == p->high || lowpc == p->high + 1) + && function == p->function) + { + if (highpc > p->high) + p->high = highpc; + return 1; + } + } + + p = ((struct function_addrs *) + backtrace_vector_grow (state, sizeof (struct function_addrs), + error_callback, data, &vec->vec)); + if (p == NULL) + return 0; + + p->low = lowpc; + p->high = highpc; + p->function = function; + ++vec->count; + return 1; +} + +/* Add PC ranges to U that map to FUNCTION. Returns 1 on success, 0 + on error. */ + +static int +add_function_ranges (struct backtrace_state *state, struct dwarf_data *ddata, + struct unit *u, struct function *function, + uint64_t ranges, uint64_t base, + backtrace_error_callback error_callback, void *data, + struct function_vector *vec) +{ + struct dwarf_buf ranges_buf; + + if (ranges >= ddata->dwarf_ranges_size) + { + error_callback (data, "function ranges offset out of range", 0); + return 0; + } + + ranges_buf.name = ".debug_ranges"; + ranges_buf.start = ddata->dwarf_ranges; + ranges_buf.buf = ddata->dwarf_ranges + ranges; + ranges_buf.left = ddata->dwarf_ranges_size - ranges; + ranges_buf.is_bigendian = ddata->is_bigendian; + ranges_buf.error_callback = error_callback; + ranges_buf.data = data; + ranges_buf.reported_underflow = 0; + + while (1) + { + uint64_t low; + uint64_t high; + + if (ranges_buf.reported_underflow) + return 0; + + low = read_address (&ranges_buf, u->addrsize); + high = read_address (&ranges_buf, u->addrsize); + + if (low == 0 && high == 0) + break; + + if (is_highest_address (low, u->addrsize)) + base = high; + else + { + if (!add_function_range (state, ddata, function, low + base, + high + base, error_callback, data, vec)) + return 0; + } + } + + if (ranges_buf.reported_underflow) + return 0; + + return 1; +} + +/* Read one entry plus all its children. Add function addresses to + VEC. Returns 1 on success, 0 on error. */ + +static int +read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, + struct unit *u, uint64_t base, struct dwarf_buf *unit_buf, + const struct line_header *lhdr, + backtrace_error_callback error_callback, void *data, + struct function_vector *vec_function, + struct function_vector *vec_inlined) +{ + while (unit_buf->left > 0) + { + uint64_t code; + const struct abbrev *abbrev; + int is_function; + struct function *function; + struct function_vector *vec; + size_t i; + uint64_t lowpc; + int have_lowpc; + uint64_t highpc; + int have_highpc; + int highpc_is_relative; + uint64_t ranges; + int have_ranges; + + code = read_uleb128 (unit_buf); + if (code == 0) + return 1; + + abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); + if (abbrev == NULL) + return 0; + + is_function = (abbrev->tag == DW_TAG_subprogram + || abbrev->tag == DW_TAG_entry_point + || abbrev->tag == DW_TAG_inlined_subroutine); + + if (abbrev->tag == DW_TAG_inlined_subroutine) + vec = vec_inlined; + else + vec = vec_function; + + function = NULL; + if (is_function) + { + function = ((struct function *) + backtrace_alloc (state, sizeof *function, + error_callback, data)); + if (function == NULL) + return 0; + memset (function, 0, sizeof *function); + } + + lowpc = 0; + have_lowpc = 0; + highpc = 0; + have_highpc = 0; + highpc_is_relative = 0; + ranges = 0; + have_ranges = 0; + for (i = 0; i < abbrev->num_attrs; ++i) + { + struct attr_val val; + + if (!read_attribute (abbrev->attrs[i].form, unit_buf, + u->is_dwarf64, u->version, u->addrsize, + ddata->dwarf_str, ddata->dwarf_str_size, + &val)) + return 0; + + /* The compile unit sets the base address for any address + ranges in the function entries. */ + if (abbrev->tag == DW_TAG_compile_unit + && abbrev->attrs[i].name == DW_AT_low_pc + && val.encoding == ATTR_VAL_ADDRESS) + base = val.u.uint; + + if (is_function) + { + switch (abbrev->attrs[i].name) + { + case DW_AT_call_file: + if (val.encoding == ATTR_VAL_UINT) + { + if (val.u.uint == 0) + function->caller_filename = ""; + else + { + if (val.u.uint - 1 >= lhdr->filenames_count) + { + dwarf_buf_error (unit_buf, + ("invalid file number in " + "DW_AT_call_file attribute")); + return 0; + } + function->caller_filename = + lhdr->filenames[val.u.uint - 1]; + } + } + break; + + case DW_AT_call_line: + if (val.encoding == ATTR_VAL_UINT) + function->caller_lineno = val.u.uint; + break; + + case DW_AT_abstract_origin: + case DW_AT_specification: + if (abbrev->attrs[i].form == DW_FORM_ref_addr + || abbrev->attrs[i].form == DW_FORM_ref_sig8) + { + /* This refers to an abstract origin defined in + some other compilation unit. We can handle + this case if we must, but it's harder. */ + break; + } + if (val.encoding == ATTR_VAL_UINT + || val.encoding == ATTR_VAL_REF_UNIT) + { + const char *name; + + name = read_referenced_name (ddata, u, val.u.uint, + error_callback, data); + if (name != NULL) + function->name = name; + } + break; + + case DW_AT_name: + if (val.encoding == ATTR_VAL_STRING) + { + /* Don't override a name we found in some other + way, as it will normally be more + useful--e.g., this name is normally not + mangled. */ + if (function->name == NULL) + function->name = val.u.string; + } + break; + + case DW_AT_linkage_name: + case DW_AT_MIPS_linkage_name: + if (val.encoding == ATTR_VAL_STRING) + function->name = val.u.string; + break; + + case DW_AT_low_pc: + if (val.encoding == ATTR_VAL_ADDRESS) + { + lowpc = val.u.uint; + have_lowpc = 1; + } + break; + + case DW_AT_high_pc: + if (val.encoding == ATTR_VAL_ADDRESS) + { + highpc = val.u.uint; + have_highpc = 1; + } + else if (val.encoding == ATTR_VAL_UINT) + { + highpc = val.u.uint; + have_highpc = 1; + highpc_is_relative = 1; + } + break; + + case DW_AT_ranges: + if (val.encoding == ATTR_VAL_UINT + || val.encoding == ATTR_VAL_REF_SECTION) + { + ranges = val.u.uint; + have_ranges = 1; + } + break; + + default: + break; + } + } + } + + /* If we couldn't find a name for the function, we have no use + for it. */ + if (is_function && function->name == NULL) + { + backtrace_free (state, function, sizeof *function, + error_callback, data); + is_function = 0; + } + + if (is_function) + { + if (have_ranges) + { + if (!add_function_ranges (state, ddata, u, function, ranges, + base, error_callback, data, vec)) + return 0; + } + else if (have_lowpc && have_highpc) + { + if (highpc_is_relative) + highpc += lowpc; + if (!add_function_range (state, ddata, function, lowpc, highpc, + error_callback, data, vec)) + return 0; + } + else + { + backtrace_free (state, function, sizeof *function, + error_callback, data); + is_function = 0; + } + } + + if (abbrev->has_children) + { + if (!is_function) + { + if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr, + error_callback, data, vec_function, + vec_inlined)) + return 0; + } + else + { + struct function_vector fvec; + + /* Gather any information for inlined functions in + FVEC. */ + + memset (&fvec, 0, sizeof fvec); + + if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr, + error_callback, data, vec_function, + &fvec)) + return 0; + + if (fvec.count > 0) + { + struct function_addrs *faddrs; + + if (!backtrace_vector_release (state, &fvec.vec, + error_callback, data)) + return 0; + + faddrs = (struct function_addrs *) fvec.vec.base; + backtrace_qsort (faddrs, fvec.count, + sizeof (struct function_addrs), + function_addrs_compare); + + function->function_addrs = faddrs; + function->function_addrs_count = fvec.count; + } + } + } + } + + return 1; +} + +/* Read function name information for a compilation unit. We look + through the whole unit looking for function tags. */ + +static void +read_function_info (struct backtrace_state *state, struct dwarf_data *ddata, + const struct line_header *lhdr, + backtrace_error_callback error_callback, void *data, + struct unit *u, struct function_vector *fvec, + struct function_addrs **ret_addrs, + size_t *ret_addrs_count) +{ + struct function_vector lvec; + struct function_vector *pfvec; + struct dwarf_buf unit_buf; + struct function_addrs *addrs; + size_t addrs_count; + + /* Use FVEC if it is not NULL. Otherwise use our own vector. */ + if (fvec != NULL) + pfvec = fvec; + else + { + memset (&lvec, 0, sizeof lvec); + pfvec = &lvec; + } + + unit_buf.name = ".debug_info"; + unit_buf.start = ddata->dwarf_info; + unit_buf.buf = u->unit_data; + unit_buf.left = u->unit_data_len; + unit_buf.is_bigendian = ddata->is_bigendian; + unit_buf.error_callback = error_callback; + unit_buf.data = data; + unit_buf.reported_underflow = 0; + + while (unit_buf.left > 0) + { + if (!read_function_entry (state, ddata, u, 0, &unit_buf, lhdr, + error_callback, data, pfvec, pfvec)) + return; + } + + if (pfvec->count == 0) + return; + + addrs_count = pfvec->count; + + if (fvec == NULL) + { + if (!backtrace_vector_release (state, &lvec.vec, error_callback, data)) + return; + addrs = (struct function_addrs *) pfvec->vec.base; + } + else + { + /* Finish this list of addresses, but leave the remaining space in + the vector available for the next function unit. */ + addrs = ((struct function_addrs *) + backtrace_vector_finish (state, &fvec->vec, + error_callback, data)); + if (addrs == NULL) + return; + fvec->count = 0; + } + + backtrace_qsort (addrs, addrs_count, sizeof (struct function_addrs), + function_addrs_compare); + + *ret_addrs = addrs; + *ret_addrs_count = addrs_count; +} + +/* See if PC is inlined in FUNCTION. If it is, print out the inlined + information, and update FILENAME and LINENO for the caller. + Returns whatever CALLBACK returns, or 0 to keep going. */ + +static int +report_inlined_functions (uintptr_t pc, struct function *function, + backtrace_full_callback callback, void *data, + const char **filename, int *lineno) +{ + struct function_addrs *function_addrs; + struct function *inlined; + int ret; + + if (function->function_addrs_count == 0) + return 0; + + function_addrs = ((struct function_addrs *) + bsearch (&pc, function->function_addrs, + function->function_addrs_count, + sizeof (struct function_addrs), + function_addrs_search)); + if (function_addrs == NULL) + return 0; + + while (((size_t) (function_addrs - function->function_addrs) + 1 + < function->function_addrs_count) + && pc >= (function_addrs + 1)->low + && pc < (function_addrs + 1)->high) + ++function_addrs; + + /* We found an inlined call. */ + + inlined = function_addrs->function; + + /* Report any calls inlined into this one. */ + ret = report_inlined_functions (pc, inlined, callback, data, + filename, lineno); + if (ret != 0) + return ret; + + /* Report this inlined call. */ + ret = callback (data, pc, *filename, *lineno, inlined->name); + if (ret != 0) + return ret; + + /* Our caller will report the caller of the inlined function; tell + it the appropriate filename and line number. */ + *filename = inlined->caller_filename; + *lineno = inlined->caller_lineno; + + return 0; +} + +/* Look for a PC in the DWARF mapping for one module. On success, + call CALLBACK and return whatever it returns. On error, call + ERROR_CALLBACK and return 0. Sets *FOUND to 1 if the PC is found, + 0 if not. */ + +static int +dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, + uintptr_t pc, backtrace_full_callback callback, + backtrace_error_callback error_callback, void *data, + int *found) +{ + struct unit_addrs *entry; + struct unit *u; + int new_data; + struct line *lines; + struct line *ln; + struct function_addrs *function_addrs; + struct function *function; + const char *filename; + int lineno; + int ret; + + *found = 1; + + /* Find an address range that includes PC. */ + entry = bsearch (&pc, ddata->addrs, ddata->addrs_count, + sizeof (struct unit_addrs), unit_addrs_search); + + if (entry == NULL) + { + *found = 0; + return 0; + } + + /* If there are multiple ranges that contain PC, use the last one, + in order to produce predictable results. If we assume that all + ranges are properly nested, then the last range will be the + smallest one. */ + while ((size_t) (entry - ddata->addrs) + 1 < ddata->addrs_count + && pc >= (entry + 1)->low + && pc < (entry + 1)->high) + ++entry; + + /* We need the lines, lines_count, function_addrs, + function_addrs_count fields of u. If they are not set, we need + to set them. When running in threaded mode, we need to allow for + the possibility that some other thread is setting them + simultaneously. */ + + u = entry->u; + lines = u->lines; + + /* Skip units with no useful line number information by walking + backward. Useless line number information is marked by setting + lines == -1. */ + while (entry > ddata->addrs + && pc >= (entry - 1)->low + && pc < (entry - 1)->high) + { + if (state->threaded) + lines = (struct line *) backtrace_atomic_load_pointer (&u->lines); + + if (lines != (struct line *) (uintptr_t) -1) + break; + + --entry; + + u = entry->u; + lines = u->lines; + } + + if (state->threaded) + lines = backtrace_atomic_load_pointer (&u->lines); + + new_data = 0; + if (lines == NULL) + { + size_t function_addrs_count; + struct line_header lhdr; + size_t count; + + /* We have never read the line information for this unit. Read + it now. */ + + function_addrs = NULL; + function_addrs_count = 0; + if (read_line_info (state, ddata, error_callback, data, entry->u, &lhdr, + &lines, &count)) + { + struct function_vector *pfvec; + + /* If not threaded, reuse DDATA->FVEC for better memory + consumption. */ + if (state->threaded) + pfvec = NULL; + else + pfvec = &ddata->fvec; + read_function_info (state, ddata, &lhdr, error_callback, data, + entry->u, pfvec, &function_addrs, + &function_addrs_count); + free_line_header (state, &lhdr, error_callback, data); + new_data = 1; + } + + /* Atomically store the information we just read into the unit. + If another thread is simultaneously writing, it presumably + read the same information, and we don't care which one we + wind up with; we just leak the other one. We do have to + write the lines field last, so that the acquire-loads above + ensure that the other fields are set. */ + + if (!state->threaded) + { + u->lines_count = count; + u->function_addrs = function_addrs; + u->function_addrs_count = function_addrs_count; + u->lines = lines; + } + else + { + backtrace_atomic_store_size_t (&u->lines_count, count); + backtrace_atomic_store_pointer (&u->function_addrs, function_addrs); + backtrace_atomic_store_size_t (&u->function_addrs_count, + function_addrs_count); + backtrace_atomic_store_pointer (&u->lines, lines); + } + } + + /* Now all fields of U have been initialized. */ + + if (lines == (struct line *) (uintptr_t) -1) + { + /* If reading the line number information failed in some way, + try again to see if there is a better compilation unit for + this PC. */ + if (new_data) + return dwarf_lookup_pc (state, ddata, pc, callback, error_callback, + data, found); + return callback (data, pc, NULL, 0, NULL); + } + + /* Search for PC within this unit. */ + + ln = (struct line *) bsearch (&pc, lines, entry->u->lines_count, + sizeof (struct line), line_search); + if (ln == NULL) + { + /* The PC is between the low_pc and high_pc attributes of the + compilation unit, but no entry in the line table covers it. + This implies that the start of the compilation unit has no + line number information. */ + + if (entry->u->abs_filename == NULL) + { + const char *filename; + + filename = entry->u->filename; + if (filename != NULL + && !IS_ABSOLUTE_PATH (filename) + && entry->u->comp_dir != NULL) + { + size_t filename_len; + const char *dir; + size_t dir_len; + char *s; + + filename_len = strlen (filename); + dir = entry->u->comp_dir; + dir_len = strlen (dir); + s = (char *) backtrace_alloc (state, dir_len + filename_len + 2, + error_callback, data); + if (s == NULL) + { + *found = 0; + return 0; + } + memcpy (s, dir, dir_len); + /* FIXME: Should use backslash if DOS file system. */ + s[dir_len] = '/'; + memcpy (s + dir_len + 1, filename, filename_len + 1); + filename = s; + } + entry->u->abs_filename = filename; + } + + return callback (data, pc, entry->u->abs_filename, 0, NULL); + } + + /* Search for function name within this unit. */ + + if (entry->u->function_addrs_count == 0) + return callback (data, pc, ln->filename, ln->lineno, NULL); + + function_addrs = ((struct function_addrs *) + bsearch (&pc, entry->u->function_addrs, + entry->u->function_addrs_count, + sizeof (struct function_addrs), + function_addrs_search)); + if (function_addrs == NULL) + return callback (data, pc, ln->filename, ln->lineno, NULL); + + /* If there are multiple function ranges that contain PC, use the + last one, in order to produce predictable results. */ + + while (((size_t) (function_addrs - entry->u->function_addrs + 1) + < entry->u->function_addrs_count) + && pc >= (function_addrs + 1)->low + && pc < (function_addrs + 1)->high) + ++function_addrs; + + function = function_addrs->function; + + filename = ln->filename; + lineno = ln->lineno; + + ret = report_inlined_functions (pc, function, callback, data, + &filename, &lineno); + if (ret != 0) + return ret; + + return callback (data, pc, filename, lineno, function->name); +} + + +/* Return the file/line information for a PC using the DWARF mapping + we built earlier. */ + +static int +dwarf_fileline (struct backtrace_state *state, uintptr_t pc, + backtrace_full_callback callback, + backtrace_error_callback error_callback, void *data) +{ + struct dwarf_data *ddata; + int found; + int ret; + + if (!state->threaded) + { + for (ddata = (struct dwarf_data *) state->fileline_data; + ddata != NULL; + ddata = ddata->next) + { + ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback, + data, &found); + if (ret != 0 || found) + return ret; + } + } + else + { + struct dwarf_data **pp; + + pp = (struct dwarf_data **) (void *) &state->fileline_data; + while (1) + { + ddata = backtrace_atomic_load_pointer (pp); + if (ddata == NULL) + break; + + ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback, + data, &found); + if (ret != 0 || found) + return ret; + + pp = &ddata->next; + } + } + + /* FIXME: See if any libraries have been dlopen'ed. */ + + return callback (data, pc, NULL, 0, NULL); +} + +/* Initialize our data structures from the DWARF debug info for a + file. Return NULL on failure. */ + +static struct dwarf_data * +build_dwarf_data (struct backtrace_state *state, + uintptr_t base_address, + const unsigned char *dwarf_info, + size_t dwarf_info_size, + const unsigned char *dwarf_line, + size_t dwarf_line_size, + const unsigned char *dwarf_abbrev, + size_t dwarf_abbrev_size, + const unsigned char *dwarf_ranges, + size_t dwarf_ranges_size, + const unsigned char *dwarf_str, + size_t dwarf_str_size, + int is_bigendian, + backtrace_error_callback error_callback, + void *data) +{ + struct unit_addrs_vector addrs_vec; + struct unit_addrs *addrs; + size_t addrs_count; + struct dwarf_data *fdata; + + if (!build_address_map (state, base_address, dwarf_info, dwarf_info_size, + dwarf_abbrev, dwarf_abbrev_size, dwarf_ranges, + dwarf_ranges_size, dwarf_str, dwarf_str_size, + is_bigendian, error_callback, data, &addrs_vec)) + return NULL; + + if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data)) + return NULL; + addrs = (struct unit_addrs *) addrs_vec.vec.base; + addrs_count = addrs_vec.count; + backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs), + unit_addrs_compare); + + fdata = ((struct dwarf_data *) + backtrace_alloc (state, sizeof (struct dwarf_data), + error_callback, data)); + if (fdata == NULL) + return NULL; + + fdata->next = NULL; + fdata->base_address = base_address; + fdata->addrs = addrs; + fdata->addrs_count = addrs_count; + fdata->dwarf_info = dwarf_info; + fdata->dwarf_info_size = dwarf_info_size; + fdata->dwarf_line = dwarf_line; + fdata->dwarf_line_size = dwarf_line_size; + fdata->dwarf_ranges = dwarf_ranges; + fdata->dwarf_ranges_size = dwarf_ranges_size; + fdata->dwarf_str = dwarf_str; + fdata->dwarf_str_size = dwarf_str_size; + fdata->is_bigendian = is_bigendian; + memset (&fdata->fvec, 0, sizeof fdata->fvec); + + return fdata; +} + +/* Build our data structures from the DWARF sections for a module. + Set FILELINE_FN and STATE->FILELINE_DATA. Return 1 on success, 0 + on failure. */ + +int +backtrace_dwarf_add (struct backtrace_state *state, + uintptr_t base_address, + const unsigned char *dwarf_info, + size_t dwarf_info_size, + const unsigned char *dwarf_line, + size_t dwarf_line_size, + const unsigned char *dwarf_abbrev, + size_t dwarf_abbrev_size, + const unsigned char *dwarf_ranges, + size_t dwarf_ranges_size, + const unsigned char *dwarf_str, + size_t dwarf_str_size, + int is_bigendian, + backtrace_error_callback error_callback, + void *data, fileline *fileline_fn) +{ + struct dwarf_data *fdata; + + fdata = build_dwarf_data (state, base_address, dwarf_info, dwarf_info_size, + dwarf_line, dwarf_line_size, dwarf_abbrev, + dwarf_abbrev_size, dwarf_ranges, dwarf_ranges_size, + dwarf_str, dwarf_str_size, is_bigendian, + error_callback, data); + if (fdata == NULL) + return 0; + + if (!state->threaded) + { + struct dwarf_data **pp; + + for (pp = (struct dwarf_data **) (void *) &state->fileline_data; + *pp != NULL; + pp = &(*pp)->next) + ; + *pp = fdata; + } + else + { + while (1) + { + struct dwarf_data **pp; + + pp = (struct dwarf_data **) (void *) &state->fileline_data; + + while (1) + { + struct dwarf_data *p; + + p = backtrace_atomic_load_pointer (pp); + + if (p == NULL) + break; + + pp = &p->next; + } + + if (__sync_bool_compare_and_swap (pp, NULL, fdata)) + break; + } + } + + *fileline_fn = dwarf_fileline; + + return 1; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/dwarf2.def b/backtrace-sys-0.1.16/src/libbacktrace/dwarf2.def new file mode 100644 index 000000000..bb916ca23 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/dwarf2.def @@ -0,0 +1,773 @@ +/* -*- c -*- + Declarations and definitions of codes relating to the DWARF2 and + DWARF3 symbolic debugging information formats. + Copyright (C) 1992-2015 Free Software Foundation, Inc. + + Written by Gary Funck (gary@intrepid.com) The Ada Joint Program + Office (AJPO), Florida State University and Silicon Graphics Inc. + provided support for this effort -- June 21, 1995. + + Derived from the DWARF 1 implementation written by Ron Guilmette + (rfg@netcom.com), November 1990. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3, or (at your option) any later + version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* This file is derived from the DWARF specification (a public document) + Revision 2.0.0 (July 27, 1993) developed by the UNIX International + Programming Languages Special Interest Group (UI/PLSIG) and distributed + by UNIX International. Copies of this specification are available from + UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. + + This file also now contains definitions from the DWARF 3 specification + published Dec 20, 2005, available from: http://dwarf.freestandards.org. + + This file also now contains definitions from the DWARF 4 + specification, available from: http://dwarfstd.org/ */ + +/* This file declares various DWARF-related constants using a set of + macros which can be redefined by the including file. + + The macros are in sections. Each section corresponds to a single + set of DWARF constants and has a corresponding key. The key is + used in all the macro names. + + The sections are TAG (for DW_TAG_ constants), FORM (DW_FORM_), AT + (DW_AT_), OP (DW_OP_), ATE (DW_ATE_), and CFA (DW_CFA_). + + Using TAG as an example, the following macros may be used for each + key: + + DW_FIRST_TAG(name, value) - Introduce the first DW_TAG constant. + + DW_TAG(name, value) - Define a subsequent constant. + + DW_TAG_DUP(name, value) - Define a subsequent constant whose value + is a duplicate of some other constant. Not all keys use the _DUP + macro form. If more than one name shares a value, then the base + (DW_TAG) form will be the preferred name and DW_TAG_DUP will hold + any alternate names. + + DW_END_TAG - Invoked at the end of the DW_TAG constants. */ + +DW_FIRST_TAG (DW_TAG_padding, 0x00) +DW_TAG (DW_TAG_array_type, 0x01) +DW_TAG (DW_TAG_class_type, 0x02) +DW_TAG (DW_TAG_entry_point, 0x03) +DW_TAG (DW_TAG_enumeration_type, 0x04) +DW_TAG (DW_TAG_formal_parameter, 0x05) +DW_TAG (DW_TAG_imported_declaration, 0x08) +DW_TAG (DW_TAG_label, 0x0a) +DW_TAG (DW_TAG_lexical_block, 0x0b) +DW_TAG (DW_TAG_member, 0x0d) +DW_TAG (DW_TAG_pointer_type, 0x0f) +DW_TAG (DW_TAG_reference_type, 0x10) +DW_TAG (DW_TAG_compile_unit, 0x11) +DW_TAG (DW_TAG_string_type, 0x12) +DW_TAG (DW_TAG_structure_type, 0x13) +DW_TAG (DW_TAG_subroutine_type, 0x15) +DW_TAG (DW_TAG_typedef, 0x16) +DW_TAG (DW_TAG_union_type, 0x17) +DW_TAG (DW_TAG_unspecified_parameters, 0x18) +DW_TAG (DW_TAG_variant, 0x19) +DW_TAG (DW_TAG_common_block, 0x1a) +DW_TAG (DW_TAG_common_inclusion, 0x1b) +DW_TAG (DW_TAG_inheritance, 0x1c) +DW_TAG (DW_TAG_inlined_subroutine, 0x1d) +DW_TAG (DW_TAG_module, 0x1e) +DW_TAG (DW_TAG_ptr_to_member_type, 0x1f) +DW_TAG (DW_TAG_set_type, 0x20) +DW_TAG (DW_TAG_subrange_type, 0x21) +DW_TAG (DW_TAG_with_stmt, 0x22) +DW_TAG (DW_TAG_access_declaration, 0x23) +DW_TAG (DW_TAG_base_type, 0x24) +DW_TAG (DW_TAG_catch_block, 0x25) +DW_TAG (DW_TAG_const_type, 0x26) +DW_TAG (DW_TAG_constant, 0x27) +DW_TAG (DW_TAG_enumerator, 0x28) +DW_TAG (DW_TAG_file_type, 0x29) +DW_TAG (DW_TAG_friend, 0x2a) +DW_TAG (DW_TAG_namelist, 0x2b) +DW_TAG (DW_TAG_namelist_item, 0x2c) +DW_TAG (DW_TAG_packed_type, 0x2d) +DW_TAG (DW_TAG_subprogram, 0x2e) +DW_TAG (DW_TAG_template_type_param, 0x2f) +DW_TAG (DW_TAG_template_value_param, 0x30) +DW_TAG (DW_TAG_thrown_type, 0x31) +DW_TAG (DW_TAG_try_block, 0x32) +DW_TAG (DW_TAG_variant_part, 0x33) +DW_TAG (DW_TAG_variable, 0x34) +DW_TAG (DW_TAG_volatile_type, 0x35) +/* DWARF 3. */ +DW_TAG (DW_TAG_dwarf_procedure, 0x36) +DW_TAG (DW_TAG_restrict_type, 0x37) +DW_TAG (DW_TAG_interface_type, 0x38) +DW_TAG (DW_TAG_namespace, 0x39) +DW_TAG (DW_TAG_imported_module, 0x3a) +DW_TAG (DW_TAG_unspecified_type, 0x3b) +DW_TAG (DW_TAG_partial_unit, 0x3c) +DW_TAG (DW_TAG_imported_unit, 0x3d) +DW_TAG (DW_TAG_condition, 0x3f) +DW_TAG (DW_TAG_shared_type, 0x40) +/* DWARF 4. */ +DW_TAG (DW_TAG_type_unit, 0x41) +DW_TAG (DW_TAG_rvalue_reference_type, 0x42) +DW_TAG (DW_TAG_template_alias, 0x43) +/* DWARF 5. */ +DW_TAG (DW_TAG_coarray_type, 0x44) +DW_TAG (DW_TAG_generic_subrange, 0x45) +DW_TAG (DW_TAG_dynamic_type, 0x46) +DW_TAG (DW_TAG_atomic_type, 0x47) +DW_TAG (DW_TAG_call_site, 0x48) +DW_TAG (DW_TAG_call_site_parameter, 0x49) +DW_TAG (DW_TAG_skeleton_unit, 0x4a) +DW_TAG (DW_TAG_immutable_type, 0x4b) + +DW_TAG_DUP (DW_TAG_lo_user, 0x4080) +DW_TAG_DUP (DW_TAG_hi_user, 0xffff) + +/* SGI/MIPS Extensions. */ +DW_TAG (DW_TAG_MIPS_loop, 0x4081) + +/* HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz . */ +DW_TAG (DW_TAG_HP_array_descriptor, 0x4090) +DW_TAG (DW_TAG_HP_Bliss_field, 0x4091) +DW_TAG (DW_TAG_HP_Bliss_field_set, 0x4092) + +/* GNU extensions. */ +DW_TAG (DW_TAG_format_label, 0x4101) /* For FORTRAN 77 and Fortran 90. */ +DW_TAG (DW_TAG_function_template, 0x4102) /* For C++. */ +DW_TAG (DW_TAG_class_template, 0x4103) /* For C++. */ +DW_TAG (DW_TAG_GNU_BINCL, 0x4104) +DW_TAG (DW_TAG_GNU_EINCL, 0x4105) +/* Template template parameter. + See http://gcc.gnu.org/wiki/TemplateParmsDwarf . */ +DW_TAG (DW_TAG_GNU_template_template_param, 0x4106) + +/* Template parameter pack extension, specified at + http://wiki.dwarfstd.org/index.php?title=C%2B%2B0x:_Variadic_templates + The values of these two TAGS are in the DW_TAG_GNU_* space until the tags + are properly part of DWARF 5. */ +DW_TAG (DW_TAG_GNU_template_parameter_pack, 0x4107) +DW_TAG (DW_TAG_GNU_formal_parameter_pack, 0x4108) +/* The GNU call site extension, specified at + http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open . + The values of these two TAGS are in the DW_TAG_GNU_* space until the tags + are properly part of DWARF 5. */ +DW_TAG (DW_TAG_GNU_call_site, 0x4109) +DW_TAG (DW_TAG_GNU_call_site_parameter, 0x410a) +/* Extensions for UPC. See: http://dwarfstd.org/doc/DWARF4.pdf. */ +DW_TAG (DW_TAG_upc_shared_type, 0x8765) +DW_TAG (DW_TAG_upc_strict_type, 0x8766) +DW_TAG (DW_TAG_upc_relaxed_type, 0x8767) +/* PGI (STMicroelectronics) extensions. No documentation available. */ +DW_TAG (DW_TAG_PGI_kanji_type, 0xA000) +DW_TAG (DW_TAG_PGI_interface_block, 0xA020) +DW_END_TAG + +DW_FIRST_FORM (DW_FORM_addr, 0x01) +DW_FORM (DW_FORM_block2, 0x03) +DW_FORM (DW_FORM_block4, 0x04) +DW_FORM (DW_FORM_data2, 0x05) +DW_FORM (DW_FORM_data4, 0x06) +DW_FORM (DW_FORM_data8, 0x07) +DW_FORM (DW_FORM_string, 0x08) +DW_FORM (DW_FORM_block, 0x09) +DW_FORM (DW_FORM_block1, 0x0a) +DW_FORM (DW_FORM_data1, 0x0b) +DW_FORM (DW_FORM_flag, 0x0c) +DW_FORM (DW_FORM_sdata, 0x0d) +DW_FORM (DW_FORM_strp, 0x0e) +DW_FORM (DW_FORM_udata, 0x0f) +DW_FORM (DW_FORM_ref_addr, 0x10) +DW_FORM (DW_FORM_ref1, 0x11) +DW_FORM (DW_FORM_ref2, 0x12) +DW_FORM (DW_FORM_ref4, 0x13) +DW_FORM (DW_FORM_ref8, 0x14) +DW_FORM (DW_FORM_ref_udata, 0x15) +DW_FORM (DW_FORM_indirect, 0x16) +/* DWARF 4. */ +DW_FORM (DW_FORM_sec_offset, 0x17) +DW_FORM (DW_FORM_exprloc, 0x18) +DW_FORM (DW_FORM_flag_present, 0x19) +DW_FORM (DW_FORM_ref_sig8, 0x20) +/* DWARF 5. */ +DW_FORM (DW_FORM_strx, 0x1a) +DW_FORM (DW_FORM_addrx, 0x1b) +DW_FORM (DW_FORM_ref_sup, 0x1c) +DW_FORM (DW_FORM_strp_sup, 0x1d) +DW_FORM (DW_FORM_data16, 0x1e) +DW_FORM (DW_FORM_line_strp, 0x1f) +DW_FORM (DW_FORM_implicit_const, 0x21) +DW_FORM (DW_FORM_loclistx, 0x22) +DW_FORM (DW_FORM_rnglistx, 0x23) +/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ +DW_FORM (DW_FORM_GNU_addr_index, 0x1f01) +DW_FORM (DW_FORM_GNU_str_index, 0x1f02) +/* Extensions for DWZ multifile. + See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open . */ +DW_FORM (DW_FORM_GNU_ref_alt, 0x1f20) +DW_FORM (DW_FORM_GNU_strp_alt, 0x1f21) +DW_END_FORM + +DW_FIRST_AT (DW_AT_sibling, 0x01) +DW_AT (DW_AT_location, 0x02) +DW_AT (DW_AT_name, 0x03) +DW_AT (DW_AT_ordering, 0x09) +DW_AT (DW_AT_subscr_data, 0x0a) +DW_AT (DW_AT_byte_size, 0x0b) +DW_AT (DW_AT_bit_offset, 0x0c) +DW_AT (DW_AT_bit_size, 0x0d) +DW_AT (DW_AT_element_list, 0x0f) +DW_AT (DW_AT_stmt_list, 0x10) +DW_AT (DW_AT_low_pc, 0x11) +DW_AT (DW_AT_high_pc, 0x12) +DW_AT (DW_AT_language, 0x13) +DW_AT (DW_AT_member, 0x14) +DW_AT (DW_AT_discr, 0x15) +DW_AT (DW_AT_discr_value, 0x16) +DW_AT (DW_AT_visibility, 0x17) +DW_AT (DW_AT_import, 0x18) +DW_AT (DW_AT_string_length, 0x19) +DW_AT (DW_AT_common_reference, 0x1a) +DW_AT (DW_AT_comp_dir, 0x1b) +DW_AT (DW_AT_const_value, 0x1c) +DW_AT (DW_AT_containing_type, 0x1d) +DW_AT (DW_AT_default_value, 0x1e) +DW_AT (DW_AT_inline, 0x20) +DW_AT (DW_AT_is_optional, 0x21) +DW_AT (DW_AT_lower_bound, 0x22) +DW_AT (DW_AT_producer, 0x25) +DW_AT (DW_AT_prototyped, 0x27) +DW_AT (DW_AT_return_addr, 0x2a) +DW_AT (DW_AT_start_scope, 0x2c) +DW_AT (DW_AT_bit_stride, 0x2e) +DW_AT (DW_AT_upper_bound, 0x2f) +DW_AT (DW_AT_abstract_origin, 0x31) +DW_AT (DW_AT_accessibility, 0x32) +DW_AT (DW_AT_address_class, 0x33) +DW_AT (DW_AT_artificial, 0x34) +DW_AT (DW_AT_base_types, 0x35) +DW_AT (DW_AT_calling_convention, 0x36) +DW_AT (DW_AT_count, 0x37) +DW_AT (DW_AT_data_member_location, 0x38) +DW_AT (DW_AT_decl_column, 0x39) +DW_AT (DW_AT_decl_file, 0x3a) +DW_AT (DW_AT_decl_line, 0x3b) +DW_AT (DW_AT_declaration, 0x3c) +DW_AT (DW_AT_discr_list, 0x3d) +DW_AT (DW_AT_encoding, 0x3e) +DW_AT (DW_AT_external, 0x3f) +DW_AT (DW_AT_frame_base, 0x40) +DW_AT (DW_AT_friend, 0x41) +DW_AT (DW_AT_identifier_case, 0x42) +DW_AT (DW_AT_macro_info, 0x43) +DW_AT (DW_AT_namelist_items, 0x44) +DW_AT (DW_AT_priority, 0x45) +DW_AT (DW_AT_segment, 0x46) +DW_AT (DW_AT_specification, 0x47) +DW_AT (DW_AT_static_link, 0x48) +DW_AT (DW_AT_type, 0x49) +DW_AT (DW_AT_use_location, 0x4a) +DW_AT (DW_AT_variable_parameter, 0x4b) +DW_AT (DW_AT_virtuality, 0x4c) +DW_AT (DW_AT_vtable_elem_location, 0x4d) +/* DWARF 3 values. */ +DW_AT (DW_AT_allocated, 0x4e) +DW_AT (DW_AT_associated, 0x4f) +DW_AT (DW_AT_data_location, 0x50) +DW_AT (DW_AT_byte_stride, 0x51) +DW_AT (DW_AT_entry_pc, 0x52) +DW_AT (DW_AT_use_UTF8, 0x53) +DW_AT (DW_AT_extension, 0x54) +DW_AT (DW_AT_ranges, 0x55) +DW_AT (DW_AT_trampoline, 0x56) +DW_AT (DW_AT_call_column, 0x57) +DW_AT (DW_AT_call_file, 0x58) +DW_AT (DW_AT_call_line, 0x59) +DW_AT (DW_AT_description, 0x5a) +DW_AT (DW_AT_binary_scale, 0x5b) +DW_AT (DW_AT_decimal_scale, 0x5c) +DW_AT (DW_AT_small, 0x5d) +DW_AT (DW_AT_decimal_sign, 0x5e) +DW_AT (DW_AT_digit_count, 0x5f) +DW_AT (DW_AT_picture_string, 0x60) +DW_AT (DW_AT_mutable, 0x61) +DW_AT (DW_AT_threads_scaled, 0x62) +DW_AT (DW_AT_explicit, 0x63) +DW_AT (DW_AT_object_pointer, 0x64) +DW_AT (DW_AT_endianity, 0x65) +DW_AT (DW_AT_elemental, 0x66) +DW_AT (DW_AT_pure, 0x67) +DW_AT (DW_AT_recursive, 0x68) +/* DWARF 4. */ +DW_AT (DW_AT_signature, 0x69) +DW_AT (DW_AT_main_subprogram, 0x6a) +DW_AT (DW_AT_data_bit_offset, 0x6b) +DW_AT (DW_AT_const_expr, 0x6c) +DW_AT (DW_AT_enum_class, 0x6d) +DW_AT (DW_AT_linkage_name, 0x6e) +/* DWARF 5. */ +DW_AT (DW_AT_string_length_bit_size, 0x6f) +DW_AT (DW_AT_string_length_byte_size, 0x70) +DW_AT (DW_AT_rank, 0x71) +DW_AT (DW_AT_str_offsets_base, 0x72) +DW_AT (DW_AT_addr_base, 0x73) +DW_AT (DW_AT_rnglists_base, 0x74) +DW_AT (DW_AT_dwo_name, 0x76) +DW_AT (DW_AT_reference, 0x77) +DW_AT (DW_AT_rvalue_reference, 0x78) +DW_AT (DW_AT_macros, 0x79) +DW_AT (DW_AT_call_all_calls, 0x7a) +DW_AT (DW_AT_call_all_source_calls, 0x7b) +DW_AT (DW_AT_call_all_tail_calls, 0x7c) +DW_AT (DW_AT_call_return_pc, 0x7d) +DW_AT (DW_AT_call_value, 0x7e) +DW_AT (DW_AT_call_origin, 0x7f) +DW_AT (DW_AT_call_parameter, 0x80) +DW_AT (DW_AT_call_pc, 0x81) +DW_AT (DW_AT_call_tail_call, 0x82) +DW_AT (DW_AT_call_target, 0x83) +DW_AT (DW_AT_call_target_clobbered, 0x84) +DW_AT (DW_AT_call_data_location, 0x85) +DW_AT (DW_AT_call_data_value, 0x86) +DW_AT (DW_AT_noreturn, 0x87) +DW_AT (DW_AT_alignment, 0x88) +DW_AT (DW_AT_export_symbols, 0x89) +DW_AT (DW_AT_deleted, 0x8a) +DW_AT (DW_AT_defaulted, 0x8b) +DW_AT (DW_AT_loclists_base, 0x8c) + +DW_AT_DUP (DW_AT_lo_user, 0x2000) /* Implementation-defined range start. */ +DW_AT_DUP (DW_AT_hi_user, 0x3fff) /* Implementation-defined range end. */ + +/* SGI/MIPS extensions. */ +DW_AT (DW_AT_MIPS_fde, 0x2001) +DW_AT (DW_AT_MIPS_loop_begin, 0x2002) +DW_AT (DW_AT_MIPS_tail_loop_begin, 0x2003) +DW_AT (DW_AT_MIPS_epilog_begin, 0x2004) +DW_AT (DW_AT_MIPS_loop_unroll_factor, 0x2005) +DW_AT (DW_AT_MIPS_software_pipeline_depth, 0x2006) +DW_AT (DW_AT_MIPS_linkage_name, 0x2007) +DW_AT (DW_AT_MIPS_stride, 0x2008) +DW_AT (DW_AT_MIPS_abstract_name, 0x2009) +DW_AT (DW_AT_MIPS_clone_origin, 0x200a) +DW_AT (DW_AT_MIPS_has_inlines, 0x200b) +/* HP extensions. */ +DW_AT (DW_AT_HP_block_index, 0x2000) +DW_AT_DUP (DW_AT_HP_unmodifiable, 0x2001) /* Same as DW_AT_MIPS_fde. */ +DW_AT_DUP (DW_AT_HP_prologue, 0x2005) /* Same as DW_AT_MIPS_loop_unroll. */ +DW_AT_DUP (DW_AT_HP_epilogue, 0x2008) /* Same as DW_AT_MIPS_stride. */ +DW_AT (DW_AT_HP_actuals_stmt_list, 0x2010) +DW_AT (DW_AT_HP_proc_per_section, 0x2011) +DW_AT (DW_AT_HP_raw_data_ptr, 0x2012) +DW_AT (DW_AT_HP_pass_by_reference, 0x2013) +DW_AT (DW_AT_HP_opt_level, 0x2014) +DW_AT (DW_AT_HP_prof_version_id, 0x2015) +DW_AT (DW_AT_HP_opt_flags, 0x2016) +DW_AT (DW_AT_HP_cold_region_low_pc, 0x2017) +DW_AT (DW_AT_HP_cold_region_high_pc, 0x2018) +DW_AT (DW_AT_HP_all_variables_modifiable, 0x2019) +DW_AT (DW_AT_HP_linkage_name, 0x201a) +DW_AT (DW_AT_HP_prof_flags, 0x201b) /* In comp unit of procs_info for -g. */ +DW_AT (DW_AT_HP_unit_name, 0x201f) +DW_AT (DW_AT_HP_unit_size, 0x2020) +DW_AT (DW_AT_HP_widened_byte_size, 0x2021) +DW_AT (DW_AT_HP_definition_points, 0x2022) +DW_AT (DW_AT_HP_default_location, 0x2023) +DW_AT (DW_AT_HP_is_result_param, 0x2029) + +/* GNU extensions. */ +DW_AT (DW_AT_sf_names, 0x2101) +DW_AT (DW_AT_src_info, 0x2102) +DW_AT (DW_AT_mac_info, 0x2103) +DW_AT (DW_AT_src_coords, 0x2104) +DW_AT (DW_AT_body_begin, 0x2105) +DW_AT (DW_AT_body_end, 0x2106) +DW_AT (DW_AT_GNU_vector, 0x2107) +/* Thread-safety annotations. + See http://gcc.gnu.org/wiki/ThreadSafetyAnnotation . */ +DW_AT (DW_AT_GNU_guarded_by, 0x2108) +DW_AT (DW_AT_GNU_pt_guarded_by, 0x2109) +DW_AT (DW_AT_GNU_guarded, 0x210a) +DW_AT (DW_AT_GNU_pt_guarded, 0x210b) +DW_AT (DW_AT_GNU_locks_excluded, 0x210c) +DW_AT (DW_AT_GNU_exclusive_locks_required, 0x210d) +DW_AT (DW_AT_GNU_shared_locks_required, 0x210e) +/* One-definition rule violation detection. + See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo . */ +DW_AT (DW_AT_GNU_odr_signature, 0x210f) +/* Template template argument name. + See http://gcc.gnu.org/wiki/TemplateParmsDwarf . */ +DW_AT (DW_AT_GNU_template_name, 0x2110) +/* The GNU call site extension. + See http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open . */ +DW_AT (DW_AT_GNU_call_site_value, 0x2111) +DW_AT (DW_AT_GNU_call_site_data_value, 0x2112) +DW_AT (DW_AT_GNU_call_site_target, 0x2113) +DW_AT (DW_AT_GNU_call_site_target_clobbered, 0x2114) +DW_AT (DW_AT_GNU_tail_call, 0x2115) +DW_AT (DW_AT_GNU_all_tail_call_sites, 0x2116) +DW_AT (DW_AT_GNU_all_call_sites, 0x2117) +DW_AT (DW_AT_GNU_all_source_call_sites, 0x2118) +/* Section offset into .debug_macro section. */ +DW_AT (DW_AT_GNU_macros, 0x2119) +/* Attribute for C++ deleted special member functions (= delete;). */ +DW_AT (DW_AT_GNU_deleted, 0x211a) +/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ +DW_AT (DW_AT_GNU_dwo_name, 0x2130) +DW_AT (DW_AT_GNU_dwo_id, 0x2131) +DW_AT (DW_AT_GNU_ranges_base, 0x2132) +DW_AT (DW_AT_GNU_addr_base, 0x2133) +DW_AT (DW_AT_GNU_pubnames, 0x2134) +DW_AT (DW_AT_GNU_pubtypes, 0x2135) +/* Attribute for discriminator. + See http://gcc.gnu.org/wiki/Discriminator */ +DW_AT (DW_AT_GNU_discriminator, 0x2136) +/* VMS extensions. */ +DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201) +/* GNAT extensions. */ +/* GNAT descriptive type. + See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type . */ +DW_AT (DW_AT_use_GNAT_descriptive_type, 0x2301) +DW_AT (DW_AT_GNAT_descriptive_type, 0x2302) +/* Rational constant extension. + See https://gcc.gnu.org/wiki/DW_AT_GNU_numerator_denominator . */ +DW_TAG (DW_AT_GNU_numerator, 0x2303) +DW_TAG (DW_AT_GNU_denominator, 0x2304) +/* Biased integer extension. + See https://gcc.gnu.org/wiki/DW_AT_GNU_bias . */ +DW_TAG (DW_AT_GNU_bias, 0x2305) +/* UPC extension. */ +DW_AT (DW_AT_upc_threads_scaled, 0x3210) +/* PGI (STMicroelectronics) extensions. */ +DW_AT (DW_AT_PGI_lbase, 0x3a00) +DW_AT (DW_AT_PGI_soffset, 0x3a01) +DW_AT (DW_AT_PGI_lstride, 0x3a02) +/* Apple extensions. */ +DW_AT (DW_AT_APPLE_optimized, 0x3fe1) +DW_AT (DW_AT_APPLE_flags, 0x3fe2) +DW_AT (DW_AT_APPLE_isa, 0x3fe3) +DW_AT (DW_AT_APPLE_block, 0x3fe4) +DW_AT (DW_AT_APPLE_major_runtime_vers, 0x3fe5) +DW_AT (DW_AT_APPLE_runtime_class, 0x3fe6) +DW_AT (DW_AT_APPLE_omit_frame_ptr, 0x3fe7) +DW_AT (DW_AT_APPLE_property_name, 0x3fe8) +DW_AT (DW_AT_APPLE_property_getter, 0x3fe9) +DW_AT (DW_AT_APPLE_property_setter, 0x3fea) +DW_AT (DW_AT_APPLE_property_attribute, 0x3feb) +DW_AT (DW_AT_APPLE_objc_complete_type, 0x3fec) +DW_AT (DW_AT_APPLE_property, 0x3fed) +DW_END_AT + +DW_FIRST_OP (DW_OP_addr, 0x03) +DW_OP (DW_OP_deref, 0x06) +DW_OP (DW_OP_const1u, 0x08) +DW_OP (DW_OP_const1s, 0x09) +DW_OP (DW_OP_const2u, 0x0a) +DW_OP (DW_OP_const2s, 0x0b) +DW_OP (DW_OP_const4u, 0x0c) +DW_OP (DW_OP_const4s, 0x0d) +DW_OP (DW_OP_const8u, 0x0e) +DW_OP (DW_OP_const8s, 0x0f) +DW_OP (DW_OP_constu, 0x10) +DW_OP (DW_OP_consts, 0x11) +DW_OP (DW_OP_dup, 0x12) +DW_OP (DW_OP_drop, 0x13) +DW_OP (DW_OP_over, 0x14) +DW_OP (DW_OP_pick, 0x15) +DW_OP (DW_OP_swap, 0x16) +DW_OP (DW_OP_rot, 0x17) +DW_OP (DW_OP_xderef, 0x18) +DW_OP (DW_OP_abs, 0x19) +DW_OP (DW_OP_and, 0x1a) +DW_OP (DW_OP_div, 0x1b) +DW_OP (DW_OP_minus, 0x1c) +DW_OP (DW_OP_mod, 0x1d) +DW_OP (DW_OP_mul, 0x1e) +DW_OP (DW_OP_neg, 0x1f) +DW_OP (DW_OP_not, 0x20) +DW_OP (DW_OP_or, 0x21) +DW_OP (DW_OP_plus, 0x22) +DW_OP (DW_OP_plus_uconst, 0x23) +DW_OP (DW_OP_shl, 0x24) +DW_OP (DW_OP_shr, 0x25) +DW_OP (DW_OP_shra, 0x26) +DW_OP (DW_OP_xor, 0x27) +DW_OP (DW_OP_bra, 0x28) +DW_OP (DW_OP_eq, 0x29) +DW_OP (DW_OP_ge, 0x2a) +DW_OP (DW_OP_gt, 0x2b) +DW_OP (DW_OP_le, 0x2c) +DW_OP (DW_OP_lt, 0x2d) +DW_OP (DW_OP_ne, 0x2e) +DW_OP (DW_OP_skip, 0x2f) +DW_OP (DW_OP_lit0, 0x30) +DW_OP (DW_OP_lit1, 0x31) +DW_OP (DW_OP_lit2, 0x32) +DW_OP (DW_OP_lit3, 0x33) +DW_OP (DW_OP_lit4, 0x34) +DW_OP (DW_OP_lit5, 0x35) +DW_OP (DW_OP_lit6, 0x36) +DW_OP (DW_OP_lit7, 0x37) +DW_OP (DW_OP_lit8, 0x38) +DW_OP (DW_OP_lit9, 0x39) +DW_OP (DW_OP_lit10, 0x3a) +DW_OP (DW_OP_lit11, 0x3b) +DW_OP (DW_OP_lit12, 0x3c) +DW_OP (DW_OP_lit13, 0x3d) +DW_OP (DW_OP_lit14, 0x3e) +DW_OP (DW_OP_lit15, 0x3f) +DW_OP (DW_OP_lit16, 0x40) +DW_OP (DW_OP_lit17, 0x41) +DW_OP (DW_OP_lit18, 0x42) +DW_OP (DW_OP_lit19, 0x43) +DW_OP (DW_OP_lit20, 0x44) +DW_OP (DW_OP_lit21, 0x45) +DW_OP (DW_OP_lit22, 0x46) +DW_OP (DW_OP_lit23, 0x47) +DW_OP (DW_OP_lit24, 0x48) +DW_OP (DW_OP_lit25, 0x49) +DW_OP (DW_OP_lit26, 0x4a) +DW_OP (DW_OP_lit27, 0x4b) +DW_OP (DW_OP_lit28, 0x4c) +DW_OP (DW_OP_lit29, 0x4d) +DW_OP (DW_OP_lit30, 0x4e) +DW_OP (DW_OP_lit31, 0x4f) +DW_OP (DW_OP_reg0, 0x50) +DW_OP (DW_OP_reg1, 0x51) +DW_OP (DW_OP_reg2, 0x52) +DW_OP (DW_OP_reg3, 0x53) +DW_OP (DW_OP_reg4, 0x54) +DW_OP (DW_OP_reg5, 0x55) +DW_OP (DW_OP_reg6, 0x56) +DW_OP (DW_OP_reg7, 0x57) +DW_OP (DW_OP_reg8, 0x58) +DW_OP (DW_OP_reg9, 0x59) +DW_OP (DW_OP_reg10, 0x5a) +DW_OP (DW_OP_reg11, 0x5b) +DW_OP (DW_OP_reg12, 0x5c) +DW_OP (DW_OP_reg13, 0x5d) +DW_OP (DW_OP_reg14, 0x5e) +DW_OP (DW_OP_reg15, 0x5f) +DW_OP (DW_OP_reg16, 0x60) +DW_OP (DW_OP_reg17, 0x61) +DW_OP (DW_OP_reg18, 0x62) +DW_OP (DW_OP_reg19, 0x63) +DW_OP (DW_OP_reg20, 0x64) +DW_OP (DW_OP_reg21, 0x65) +DW_OP (DW_OP_reg22, 0x66) +DW_OP (DW_OP_reg23, 0x67) +DW_OP (DW_OP_reg24, 0x68) +DW_OP (DW_OP_reg25, 0x69) +DW_OP (DW_OP_reg26, 0x6a) +DW_OP (DW_OP_reg27, 0x6b) +DW_OP (DW_OP_reg28, 0x6c) +DW_OP (DW_OP_reg29, 0x6d) +DW_OP (DW_OP_reg30, 0x6e) +DW_OP (DW_OP_reg31, 0x6f) +DW_OP (DW_OP_breg0, 0x70) +DW_OP (DW_OP_breg1, 0x71) +DW_OP (DW_OP_breg2, 0x72) +DW_OP (DW_OP_breg3, 0x73) +DW_OP (DW_OP_breg4, 0x74) +DW_OP (DW_OP_breg5, 0x75) +DW_OP (DW_OP_breg6, 0x76) +DW_OP (DW_OP_breg7, 0x77) +DW_OP (DW_OP_breg8, 0x78) +DW_OP (DW_OP_breg9, 0x79) +DW_OP (DW_OP_breg10, 0x7a) +DW_OP (DW_OP_breg11, 0x7b) +DW_OP (DW_OP_breg12, 0x7c) +DW_OP (DW_OP_breg13, 0x7d) +DW_OP (DW_OP_breg14, 0x7e) +DW_OP (DW_OP_breg15, 0x7f) +DW_OP (DW_OP_breg16, 0x80) +DW_OP (DW_OP_breg17, 0x81) +DW_OP (DW_OP_breg18, 0x82) +DW_OP (DW_OP_breg19, 0x83) +DW_OP (DW_OP_breg20, 0x84) +DW_OP (DW_OP_breg21, 0x85) +DW_OP (DW_OP_breg22, 0x86) +DW_OP (DW_OP_breg23, 0x87) +DW_OP (DW_OP_breg24, 0x88) +DW_OP (DW_OP_breg25, 0x89) +DW_OP (DW_OP_breg26, 0x8a) +DW_OP (DW_OP_breg27, 0x8b) +DW_OP (DW_OP_breg28, 0x8c) +DW_OP (DW_OP_breg29, 0x8d) +DW_OP (DW_OP_breg30, 0x8e) +DW_OP (DW_OP_breg31, 0x8f) +DW_OP (DW_OP_regx, 0x90) +DW_OP (DW_OP_fbreg, 0x91) +DW_OP (DW_OP_bregx, 0x92) +DW_OP (DW_OP_piece, 0x93) +DW_OP (DW_OP_deref_size, 0x94) +DW_OP (DW_OP_xderef_size, 0x95) +DW_OP (DW_OP_nop, 0x96) +/* DWARF 3 extensions. */ +DW_OP (DW_OP_push_object_address, 0x97) +DW_OP (DW_OP_call2, 0x98) +DW_OP (DW_OP_call4, 0x99) +DW_OP (DW_OP_call_ref, 0x9a) +DW_OP (DW_OP_form_tls_address, 0x9b) +DW_OP (DW_OP_call_frame_cfa, 0x9c) +DW_OP (DW_OP_bit_piece, 0x9d) + +/* DWARF 4 extensions. */ +DW_OP (DW_OP_implicit_value, 0x9e) +DW_OP (DW_OP_stack_value, 0x9f) + +/* DWARF 5 extensions. */ +DW_OP (DW_OP_implicit_pointer, 0xa0) +DW_OP (DW_OP_addrx, 0xa1) +DW_OP (DW_OP_constx, 0xa2) +DW_OP (DW_OP_entry_value, 0xa3) +DW_OP (DW_OP_const_type, 0xa4) +DW_OP (DW_OP_regval_type, 0xa5) +DW_OP (DW_OP_deref_type, 0xa6) +DW_OP (DW_OP_xderef_type, 0xa7) +DW_OP (DW_OP_convert, 0xa8) +DW_OP (DW_OP_reinterpret, 0xa9) + +DW_OP_DUP (DW_OP_lo_user, 0xe0) /* Implementation-defined range start. */ +DW_OP_DUP (DW_OP_hi_user, 0xff) /* Implementation-defined range end. */ + +/* GNU extensions. */ +DW_OP (DW_OP_GNU_push_tls_address, 0xe0) +/* The following is for marking variables that are uninitialized. */ +DW_OP (DW_OP_GNU_uninit, 0xf0) +DW_OP (DW_OP_GNU_encoded_addr, 0xf1) +/* The GNU implicit pointer extension. + See http://www.dwarfstd.org/ShowIssue.php?issue=100831.1&type=open . */ +DW_OP (DW_OP_GNU_implicit_pointer, 0xf2) +/* The GNU entry value extension. + See http://www.dwarfstd.org/ShowIssue.php?issue=100909.1&type=open . */ +DW_OP (DW_OP_GNU_entry_value, 0xf3) +/* The GNU typed stack extension. + See http://www.dwarfstd.org/doc/040408.1.html . */ +DW_OP (DW_OP_GNU_const_type, 0xf4) +DW_OP (DW_OP_GNU_regval_type, 0xf5) +DW_OP (DW_OP_GNU_deref_type, 0xf6) +DW_OP (DW_OP_GNU_convert, 0xf7) +DW_OP (DW_OP_GNU_reinterpret, 0xf9) +/* The GNU parameter ref extension. */ +DW_OP (DW_OP_GNU_parameter_ref, 0xfa) +/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ +DW_OP (DW_OP_GNU_addr_index, 0xfb) +DW_OP (DW_OP_GNU_const_index, 0xfc) +/* HP extensions. */ +DW_OP_DUP (DW_OP_HP_unknown, 0xe0) /* Ouch, the same as GNU_push_tls_address. */ +DW_OP (DW_OP_HP_is_value, 0xe1) +DW_OP (DW_OP_HP_fltconst4, 0xe2) +DW_OP (DW_OP_HP_fltconst8, 0xe3) +DW_OP (DW_OP_HP_mod_range, 0xe4) +DW_OP (DW_OP_HP_unmod_range, 0xe5) +DW_OP (DW_OP_HP_tls, 0xe6) +/* PGI (STMicroelectronics) extensions. */ +DW_OP (DW_OP_PGI_omp_thread_num, 0xf8) +DW_END_OP + +DW_FIRST_ATE (DW_ATE_void, 0x0) +DW_ATE (DW_ATE_address, 0x1) +DW_ATE (DW_ATE_boolean, 0x2) +DW_ATE (DW_ATE_complex_float, 0x3) +DW_ATE (DW_ATE_float, 0x4) +DW_ATE (DW_ATE_signed, 0x5) +DW_ATE (DW_ATE_signed_char, 0x6) +DW_ATE (DW_ATE_unsigned, 0x7) +DW_ATE (DW_ATE_unsigned_char, 0x8) +/* DWARF 3. */ +DW_ATE (DW_ATE_imaginary_float, 0x9) +DW_ATE (DW_ATE_packed_decimal, 0xa) +DW_ATE (DW_ATE_numeric_string, 0xb) +DW_ATE (DW_ATE_edited, 0xc) +DW_ATE (DW_ATE_signed_fixed, 0xd) +DW_ATE (DW_ATE_unsigned_fixed, 0xe) +DW_ATE (DW_ATE_decimal_float, 0xf) +/* DWARF 4. */ +DW_ATE (DW_ATE_UTF, 0x10) +/* DWARF 5. */ +DW_ATE (DW_ATE_UCS, 0x11) +DW_ATE (DW_ATE_ASCII, 0x12) + +DW_ATE_DUP (DW_ATE_lo_user, 0x80) +DW_ATE_DUP (DW_ATE_hi_user, 0xff) + +/* HP extensions. */ +DW_ATE (DW_ATE_HP_float80, 0x80) /* Floating-point (80 bit). */ +DW_ATE (DW_ATE_HP_complex_float80, 0x81) /* Complex floating-point (80 bit). */ +DW_ATE (DW_ATE_HP_float128, 0x82) /* Floating-point (128 bit). */ +DW_ATE (DW_ATE_HP_complex_float128, 0x83) /* Complex fp (128 bit). */ +DW_ATE (DW_ATE_HP_floathpintel, 0x84) /* Floating-point (82 bit IA64). */ +DW_ATE (DW_ATE_HP_imaginary_float80, 0x85) +DW_ATE (DW_ATE_HP_imaginary_float128, 0x86) +DW_ATE (DW_ATE_HP_VAX_float, 0x88) /* F or G floating. */ +DW_ATE (DW_ATE_HP_VAX_float_d, 0x89) /* D floating. */ +DW_ATE (DW_ATE_HP_packed_decimal, 0x8a) /* Cobol. */ +DW_ATE (DW_ATE_HP_zoned_decimal, 0x8b) /* Cobol. */ +DW_ATE (DW_ATE_HP_edited, 0x8c) /* Cobol. */ +DW_ATE (DW_ATE_HP_signed_fixed, 0x8d) /* Cobol. */ +DW_ATE (DW_ATE_HP_unsigned_fixed, 0x8e) /* Cobol. */ +DW_ATE (DW_ATE_HP_VAX_complex_float, 0x8f) /* F or G floating complex. */ +DW_ATE (DW_ATE_HP_VAX_complex_float_d, 0x90) /* D floating complex. */ + +DW_END_ATE + +DW_FIRST_CFA (DW_CFA_advance_loc, 0x40) +DW_CFA (DW_CFA_offset, 0x80) +DW_CFA (DW_CFA_restore, 0xc0) +DW_CFA (DW_CFA_nop, 0x00) +DW_CFA (DW_CFA_set_loc, 0x01) +DW_CFA (DW_CFA_advance_loc1, 0x02) +DW_CFA (DW_CFA_advance_loc2, 0x03) +DW_CFA (DW_CFA_advance_loc4, 0x04) +DW_CFA (DW_CFA_offset_extended, 0x05) +DW_CFA (DW_CFA_restore_extended, 0x06) +DW_CFA (DW_CFA_undefined, 0x07) +DW_CFA (DW_CFA_same_value, 0x08) +DW_CFA (DW_CFA_register, 0x09) +DW_CFA (DW_CFA_remember_state, 0x0a) +DW_CFA (DW_CFA_restore_state, 0x0b) +DW_CFA (DW_CFA_def_cfa, 0x0c) +DW_CFA (DW_CFA_def_cfa_register, 0x0d) +DW_CFA (DW_CFA_def_cfa_offset, 0x0e) +/* DWARF 3. */ +DW_CFA (DW_CFA_def_cfa_expression, 0x0f) +DW_CFA (DW_CFA_expression, 0x10) +DW_CFA (DW_CFA_offset_extended_sf, 0x11) +DW_CFA (DW_CFA_def_cfa_sf, 0x12) +DW_CFA (DW_CFA_def_cfa_offset_sf, 0x13) +DW_CFA (DW_CFA_val_offset, 0x14) +DW_CFA (DW_CFA_val_offset_sf, 0x15) +DW_CFA (DW_CFA_val_expression, 0x16) + +DW_CFA (DW_CFA_lo_user, 0x1c) +DW_CFA (DW_CFA_hi_user, 0x3f) + +/* SGI/MIPS specific. */ +DW_CFA (DW_CFA_MIPS_advance_loc8, 0x1d) +/* GNU extensions. */ +DW_CFA (DW_CFA_GNU_window_save, 0x2d) +DW_CFA (DW_CFA_GNU_args_size, 0x2e) +DW_CFA (DW_CFA_GNU_negative_offset_extended, 0x2f) + +DW_END_CFA diff --git a/backtrace-sys-0.1.16/src/libbacktrace/dwarf2.h b/backtrace-sys-0.1.16/src/libbacktrace/dwarf2.h new file mode 100644 index 000000000..ca8ff3b6d --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/dwarf2.h @@ -0,0 +1,531 @@ +/* Declarations and definitions of codes relating to the DWARF2 and + DWARF3 symbolic debugging information formats. + Copyright (C) 1992-2016 Free Software Foundation, Inc. + + Written by Gary Funck (gary@intrepid.com) The Ada Joint Program + Office (AJPO), Florida State University and Silicon Graphics Inc. + provided support for this effort -- June 21, 1995. + + Derived from the DWARF 1 implementation written by Ron Guilmette + (rfg@netcom.com), November 1990. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3, or (at your option) any later + version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* This file is derived from the DWARF specification (a public document) + Revision 2.0.0 (July 27, 1993) developed by the UNIX International + Programming Languages Special Interest Group (UI/PLSIG) and distributed + by UNIX International. Copies of this specification are available from + UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. + + This file also now contains definitions from the DWARF 3 specification + published Dec 20, 2005, available from: http://dwarf.freestandards.org. */ + +#ifndef _DWARF2_H +#define _DWARF2_H + +#define DW_TAG(name, value) , name = value +#define DW_TAG_DUP(name, value) , name = value +#define DW_FORM(name, value) , name = value +#define DW_AT(name, value) , name = value +#define DW_AT_DUP(name, value) , name = value +#define DW_OP(name, value) , name = value +#define DW_OP_DUP(name, value) , name = value +#define DW_ATE(name, value) , name = value +#define DW_ATE_DUP(name, value) , name = value +#define DW_CFA(name, value) , name = value + +#define DW_FIRST_TAG(name, value) enum dwarf_tag { \ + name = value +#define DW_END_TAG }; +#define DW_FIRST_FORM(name, value) enum dwarf_form { \ + name = value +#define DW_END_FORM }; +#define DW_FIRST_AT(name, value) enum dwarf_attribute { \ + name = value +#define DW_END_AT }; +#define DW_FIRST_OP(name, value) enum dwarf_location_atom { \ + name = value +#define DW_END_OP }; +#define DW_FIRST_ATE(name, value) enum dwarf_type { \ + name = value +#define DW_END_ATE }; +#define DW_FIRST_CFA(name, value) enum dwarf_call_frame_info { \ + name = value +#define DW_END_CFA }; + +#include "dwarf2.def" + +#undef DW_FIRST_TAG +#undef DW_END_TAG +#undef DW_FIRST_FORM +#undef DW_END_FORM +#undef DW_FIRST_AT +#undef DW_END_AT +#undef DW_FIRST_OP +#undef DW_END_OP +#undef DW_FIRST_ATE +#undef DW_END_ATE +#undef DW_FIRST_CFA +#undef DW_END_CFA + +#undef DW_TAG +#undef DW_TAG_DUP +#undef DW_FORM +#undef DW_AT +#undef DW_AT_DUP +#undef DW_OP +#undef DW_OP_DUP +#undef DW_ATE +#undef DW_ATE_DUP +#undef DW_CFA + +/* Flag that tells whether entry has a child or not. */ +#define DW_children_no 0 +#define DW_children_yes 1 + +#define DW_AT_stride_size DW_AT_bit_stride /* Note: The use of DW_AT_stride_size is deprecated. */ +#define DW_AT_stride DW_AT_byte_stride /* Note: The use of DW_AT_stride is deprecated. */ + +/* Decimal sign encodings. */ +enum dwarf_decimal_sign_encoding + { + /* DWARF 3. */ + DW_DS_unsigned = 0x01, + DW_DS_leading_overpunch = 0x02, + DW_DS_trailing_overpunch = 0x03, + DW_DS_leading_separate = 0x04, + DW_DS_trailing_separate = 0x05 + }; + +/* Endianity encodings. */ +enum dwarf_endianity_encoding + { + /* DWARF 3. */ + DW_END_default = 0x00, + DW_END_big = 0x01, + DW_END_little = 0x02, + + DW_END_lo_user = 0x40, + DW_END_hi_user = 0xff + }; + +/* Array ordering names and codes. */ +enum dwarf_array_dim_ordering + { + DW_ORD_row_major = 0, + DW_ORD_col_major = 1 + }; + +/* Access attribute. */ +enum dwarf_access_attribute + { + DW_ACCESS_public = 1, + DW_ACCESS_protected = 2, + DW_ACCESS_private = 3 + }; + +/* Visibility. */ +enum dwarf_visibility_attribute + { + DW_VIS_local = 1, + DW_VIS_exported = 2, + DW_VIS_qualified = 3 + }; + +/* Virtuality. */ +enum dwarf_virtuality_attribute + { + DW_VIRTUALITY_none = 0, + DW_VIRTUALITY_virtual = 1, + DW_VIRTUALITY_pure_virtual = 2 + }; + +/* Case sensitivity. */ +enum dwarf_id_case + { + DW_ID_case_sensitive = 0, + DW_ID_up_case = 1, + DW_ID_down_case = 2, + DW_ID_case_insensitive = 3 + }; + +/* Calling convention. */ +enum dwarf_calling_convention + { + DW_CC_normal = 0x1, + DW_CC_program = 0x2, + DW_CC_nocall = 0x3, + + /* DWARF 5. */ + DW_CC_pass_by_reference = 0x4, + DW_CC_pass_by_value = 0x5, + + DW_CC_lo_user = 0x40, + DW_CC_hi_user = 0xff, + + DW_CC_GNU_renesas_sh = 0x40, + DW_CC_GNU_borland_fastcall_i386 = 0x41, + + /* This DW_CC_ value is not currently generated by any toolchain. It is + used internally to GDB to indicate OpenCL C functions that have been + compiled with the IBM XL C for OpenCL compiler and use a non-platform + calling convention for passing OpenCL C vector types. This value may + be changed freely as long as it does not conflict with any other DW_CC_ + value defined here. */ + DW_CC_GDB_IBM_OpenCL = 0xff + }; + +/* Inline attribute. */ +enum dwarf_inline_attribute + { + DW_INL_not_inlined = 0, + DW_INL_inlined = 1, + DW_INL_declared_not_inlined = 2, + DW_INL_declared_inlined = 3 + }; + +/* Discriminant lists. */ +enum dwarf_discrim_list + { + DW_DSC_label = 0, + DW_DSC_range = 1 + }; + +/* Line number opcodes. */ +enum dwarf_line_number_ops + { + DW_LNS_extended_op = 0, + DW_LNS_copy = 1, + DW_LNS_advance_pc = 2, + DW_LNS_advance_line = 3, + DW_LNS_set_file = 4, + DW_LNS_set_column = 5, + DW_LNS_negate_stmt = 6, + DW_LNS_set_basic_block = 7, + DW_LNS_const_add_pc = 8, + DW_LNS_fixed_advance_pc = 9, + /* DWARF 3. */ + DW_LNS_set_prologue_end = 10, + DW_LNS_set_epilogue_begin = 11, + DW_LNS_set_isa = 12 + }; + +/* Line number extended opcodes. */ +enum dwarf_line_number_x_ops + { + DW_LNE_end_sequence = 1, + DW_LNE_set_address = 2, + DW_LNE_define_file = 3, + DW_LNE_set_discriminator = 4, + /* HP extensions. */ + DW_LNE_HP_negate_is_UV_update = 0x11, + DW_LNE_HP_push_context = 0x12, + DW_LNE_HP_pop_context = 0x13, + DW_LNE_HP_set_file_line_column = 0x14, + DW_LNE_HP_set_routine_name = 0x15, + DW_LNE_HP_set_sequence = 0x16, + DW_LNE_HP_negate_post_semantics = 0x17, + DW_LNE_HP_negate_function_exit = 0x18, + DW_LNE_HP_negate_front_end_logical = 0x19, + DW_LNE_HP_define_proc = 0x20, + DW_LNE_HP_source_file_correlation = 0x80, + + DW_LNE_lo_user = 0x80, + DW_LNE_hi_user = 0xff + }; + +/* Sub-opcodes for DW_LNE_HP_source_file_correlation. */ +enum dwarf_line_number_hp_sfc_ops + { + DW_LNE_HP_SFC_formfeed = 1, + DW_LNE_HP_SFC_set_listing_line = 2, + DW_LNE_HP_SFC_associate = 3 + }; + +/* Content type codes in line table directory_entry_format + and file_name_entry_format sequences. */ +enum dwarf_line_number_content_type + { + DW_LNCT_path = 0x1, + DW_LNCT_directory_index = 0x2, + DW_LNCT_timestamp = 0x3, + DW_LNCT_size = 0x4, + DW_LNCT_MD5 = 0x5, + DW_LNCT_lo_user = 0x2000, + DW_LNCT_hi_user = 0x3fff + }; + +/* Type codes for location list entries. */ +enum dwarf_location_list_entry_type + { + DW_LLE_end_of_list = 0x00, + DW_LLE_base_addressx = 0x01, + DW_LLE_startx_endx = 0x02, + DW_LLE_startx_length = 0x03, + DW_LLE_offset_pair = 0x04, + DW_LLE_default_location = 0x05, + DW_LLE_base_address = 0x06, + DW_LLE_start_end = 0x07, + DW_LLE_start_length = 0x08, + + /* Former extension for Fission. + See http://gcc.gnu.org/wiki/DebugFission. */ + DW_LLE_GNU_end_of_list_entry = 0x00, + DW_LLE_GNU_base_address_selection_entry = 0x01, + DW_LLE_GNU_start_end_entry = 0x02, + DW_LLE_GNU_start_length_entry = 0x03 + }; + +#define DW_CIE_ID 0xffffffff +#define DW64_CIE_ID 0xffffffffffffffffULL +#define DW_CIE_VERSION 1 + +#define DW_CFA_extended 0 + +#define DW_CHILDREN_no 0x00 +#define DW_CHILDREN_yes 0x01 + +#define DW_ADDR_none 0 + +/* Source language names and codes. */ +enum dwarf_source_language + { + DW_LANG_C89 = 0x0001, + DW_LANG_C = 0x0002, + DW_LANG_Ada83 = 0x0003, + DW_LANG_C_plus_plus = 0x0004, + DW_LANG_Cobol74 = 0x0005, + DW_LANG_Cobol85 = 0x0006, + DW_LANG_Fortran77 = 0x0007, + DW_LANG_Fortran90 = 0x0008, + DW_LANG_Pascal83 = 0x0009, + DW_LANG_Modula2 = 0x000a, + /* DWARF 3. */ + DW_LANG_Java = 0x000b, + DW_LANG_C99 = 0x000c, + DW_LANG_Ada95 = 0x000d, + DW_LANG_Fortran95 = 0x000e, + DW_LANG_PLI = 0x000f, + DW_LANG_ObjC = 0x0010, + DW_LANG_ObjC_plus_plus = 0x0011, + DW_LANG_UPC = 0x0012, + DW_LANG_D = 0x0013, + /* DWARF 4. */ + DW_LANG_Python = 0x0014, + /* DWARF 5. */ + DW_LANG_OpenCL = 0x0015, + DW_LANG_Go = 0x0016, + DW_LANG_Modula3 = 0x0017, + DW_LANG_Haskell = 0x0018, + DW_LANG_C_plus_plus_03 = 0x0019, + DW_LANG_C_plus_plus_11 = 0x001a, + DW_LANG_OCaml = 0x001b, + DW_LANG_Rust = 0x001c, + DW_LANG_C11 = 0x001d, + DW_LANG_Swift = 0x001e, + DW_LANG_Julia = 0x001f, + DW_LANG_Dylan = 0x0020, + DW_LANG_C_plus_plus_14 = 0x0021, + DW_LANG_Fortran03 = 0x0022, + DW_LANG_Fortran08 = 0x0023, + DW_LANG_RenderScript = 0x0024, + + DW_LANG_lo_user = 0x8000, /* Implementation-defined range start. */ + DW_LANG_hi_user = 0xffff, /* Implementation-defined range start. */ + + /* MIPS. */ + DW_LANG_Mips_Assembler = 0x8001, + /* UPC. */ + DW_LANG_Upc = 0x8765, + /* HP extensions. */ + DW_LANG_HP_Bliss = 0x8003, + DW_LANG_HP_Basic91 = 0x8004, + DW_LANG_HP_Pascal91 = 0x8005, + DW_LANG_HP_IMacro = 0x8006, + DW_LANG_HP_Assembler = 0x8007, + + /* Rust extension, but replaced in DWARF 5. */ + DW_LANG_Rust_old = 0x9000 + }; + +/* Names and codes for macro information. */ +enum dwarf_macinfo_record_type + { + DW_MACINFO_define = 1, + DW_MACINFO_undef = 2, + DW_MACINFO_start_file = 3, + DW_MACINFO_end_file = 4, + DW_MACINFO_vendor_ext = 255 + }; + +/* DW_TAG_defaulted/DW_TAG_GNU_defaulted attributes. */ +enum dwarf_defaulted_attribute + { + DW_DEFAULTED_no = 0x00, + DW_DEFAULTED_in_class = 0x01, + DW_DEFAULTED_out_of_class = 0x02 + }; + +/* Names and codes for new style macro information. */ +enum dwarf_macro_record_type + { + DW_MACRO_define = 0x01, + DW_MACRO_undef = 0x02, + DW_MACRO_start_file = 0x03, + DW_MACRO_end_file = 0x04, + DW_MACRO_define_strp = 0x05, + DW_MACRO_undef_strp = 0x06, + DW_MACRO_import = 0x07, + DW_MACRO_define_sup = 0x08, + DW_MACRO_undef_sup = 0x09, + DW_MACRO_import_sup = 0x0a, + DW_MACRO_define_strx = 0x0b, + DW_MACRO_undef_strx = 0x0c, + DW_MACRO_lo_user = 0xe0, + DW_MACRO_hi_user = 0xff, + + /* Compatibility macros for the GNU .debug_macro extension. */ + DW_MACRO_GNU_define = 0x01, + DW_MACRO_GNU_undef = 0x02, + DW_MACRO_GNU_start_file = 0x03, + DW_MACRO_GNU_end_file = 0x04, + DW_MACRO_GNU_define_indirect = 0x05, + DW_MACRO_GNU_undef_indirect = 0x06, + DW_MACRO_GNU_transparent_include = 0x07, + /* Extensions for DWZ multifile. + See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open . */ + DW_MACRO_GNU_define_indirect_alt = 0x08, + DW_MACRO_GNU_undef_indirect_alt = 0x09, + DW_MACRO_GNU_transparent_include_alt = 0x0a, + DW_MACRO_GNU_lo_user = 0xe0, + DW_MACRO_GNU_hi_user = 0xff + }; + +/* Index attributes in the Abbreviations Table. */ +enum dwarf_name_index_attribute + { + DW_IDX_compile_unit = 1, + DW_IDX_type_unit = 2, + DW_IDX_die_offset = 3, + DW_IDX_parent = 4, + DW_IDX_type_hash = 5, + DW_IDX_lo_user = 0x2000, + DW_IDX_hi_user = 0x3fff + }; + +/* Range list entry kinds in .debug_rnglists* section. */ +enum dwarf_range_list_entry + { + DW_RLE_end_of_list = 0x00, + DW_RLE_base_addressx = 0x01, + DW_RLE_startx_endx = 0x02, + DW_RLE_startx_length = 0x03, + DW_RLE_offset_pair = 0x04, + DW_RLE_base_address = 0x05, + DW_RLE_start_end = 0x06, + DW_RLE_start_length = 0x07 + }; + +/* Unit types in unit_type unit header field. */ +enum dwarf_unit_type + { + DW_UT_compile = 0x01, + DW_UT_type = 0x02, + DW_UT_partial = 0x03, + DW_UT_skeleton = 0x04, + DW_UT_split_compile = 0x05, + DW_UT_split_type = 0x06, + DW_UT_lo_user = 0x80, + DW_UT_hi_user = 0xff + }; + +/* @@@ For use with GNU frame unwind information. */ + +#define DW_EH_PE_absptr 0x00 +#define DW_EH_PE_omit 0xff + +#define DW_EH_PE_uleb128 0x01 +#define DW_EH_PE_udata2 0x02 +#define DW_EH_PE_udata4 0x03 +#define DW_EH_PE_udata8 0x04 +#define DW_EH_PE_sleb128 0x09 +#define DW_EH_PE_sdata2 0x0A +#define DW_EH_PE_sdata4 0x0B +#define DW_EH_PE_sdata8 0x0C +#define DW_EH_PE_signed 0x08 + +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_textrel 0x20 +#define DW_EH_PE_datarel 0x30 +#define DW_EH_PE_funcrel 0x40 +#define DW_EH_PE_aligned 0x50 + +#define DW_EH_PE_indirect 0x80 + +/* Codes for the debug sections in a dwarf package (.dwp) file. + Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFissionDWP. */ +enum dwarf_sect + { + DW_SECT_INFO = 1, + DW_SECT_TYPES = 2, + DW_SECT_ABBREV = 3, + DW_SECT_LINE = 4, + DW_SECT_LOC = 5, + DW_SECT_STR_OFFSETS = 6, + DW_SECT_MACINFO = 7, + DW_SECT_MACRO = 8, + DW_SECT_MAX = 8 + }; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Return the name of a DW_TAG_ constant, or NULL if the value is not + recognized. */ +extern const char *get_DW_TAG_name (unsigned int tag); + +/* Return the name of a DW_AT_ constant, or NULL if the value is not + recognized. */ +extern const char *get_DW_AT_name (unsigned int attr); + +/* Return the name of a DW_FORM_ constant, or NULL if the value is not + recognized. */ +extern const char *get_DW_FORM_name (unsigned int form); + +/* Return the name of a DW_OP_ constant, or NULL if the value is not + recognized. */ +extern const char *get_DW_OP_name (unsigned int op); + +/* Return the name of a DW_ATE_ constant, or NULL if the value is not + recognized. */ +extern const char *get_DW_ATE_name (unsigned int enc); + +/* Return the name of a DW_CFA_ constant, or NULL if the value is not + recognized. */ +extern const char *get_DW_CFA_name (unsigned int opc); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _DWARF2_H */ diff --git a/backtrace-sys-0.1.16/src/libbacktrace/elf.c b/backtrace-sys-0.1.16/src/libbacktrace/elf.c new file mode 100644 index 000000000..e87741382 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/elf.c @@ -0,0 +1,979 @@ +/* elf.c -- Get debug data from an ELF file for backtraces. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include +#include + +#ifdef HAVE_DL_ITERATE_PHDR +#include +#endif + +#include "backtrace.h" +#include "internal.h" + +#ifndef HAVE_DL_ITERATE_PHDR + +/* Dummy version of dl_iterate_phdr for systems that don't have it. */ + +#define dl_phdr_info x_dl_phdr_info +#define dl_iterate_phdr x_dl_iterate_phdr + +struct dl_phdr_info +{ + uintptr_t dlpi_addr; + const char *dlpi_name; +}; + +static int +dl_iterate_phdr (int (*callback) (struct dl_phdr_info *, + size_t, void *) ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + return 0; +} + +#endif /* ! defined (HAVE_DL_ITERATE_PHDR) */ + +/* The configure script must tell us whether we are 32-bit or 64-bit + ELF. We could make this code test and support either possibility, + but there is no point. This code only works for the currently + running executable, which means that we know the ELF mode at + configure mode. */ + +#if BACKTRACE_ELF_SIZE != 32 && BACKTRACE_ELF_SIZE != 64 +#error "Unknown BACKTRACE_ELF_SIZE" +#endif + +/* might #include which might define our constants + with slightly different values. Undefine them to be safe. */ + +#undef EI_NIDENT +#undef EI_MAG0 +#undef EI_MAG1 +#undef EI_MAG2 +#undef EI_MAG3 +#undef EI_CLASS +#undef EI_DATA +#undef EI_VERSION +#undef ELF_MAG0 +#undef ELF_MAG1 +#undef ELF_MAG2 +#undef ELF_MAG3 +#undef ELFCLASS32 +#undef ELFCLASS64 +#undef ELFDATA2LSB +#undef ELFDATA2MSB +#undef EV_CURRENT +#undef ET_DYN +#undef SHN_LORESERVE +#undef SHN_XINDEX +#undef SHN_UNDEF +#undef SHT_SYMTAB +#undef SHT_STRTAB +#undef SHT_DYNSYM +#undef STT_OBJECT +#undef STT_FUNC + +/* Basic types. */ + +typedef uint16_t b_elf_half; /* Elf_Half. */ +typedef uint32_t b_elf_word; /* Elf_Word. */ +typedef int32_t b_elf_sword; /* Elf_Sword. */ + +#if BACKTRACE_ELF_SIZE == 32 + +typedef uint32_t b_elf_addr; /* Elf_Addr. */ +typedef uint32_t b_elf_off; /* Elf_Off. */ + +typedef uint32_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */ + +#else + +typedef uint64_t b_elf_addr; /* Elf_Addr. */ +typedef uint64_t b_elf_off; /* Elf_Off. */ +typedef uint64_t b_elf_xword; /* Elf_Xword. */ +typedef int64_t b_elf_sxword; /* Elf_Sxword. */ + +typedef uint64_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */ + +#endif + +/* Data structures and associated constants. */ + +#define EI_NIDENT 16 + +typedef struct { + unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ + b_elf_half e_type; /* Identifies object file type */ + b_elf_half e_machine; /* Specifies required architecture */ + b_elf_word e_version; /* Identifies object file version */ + b_elf_addr e_entry; /* Entry point virtual address */ + b_elf_off e_phoff; /* Program header table file offset */ + b_elf_off e_shoff; /* Section header table file offset */ + b_elf_word e_flags; /* Processor-specific flags */ + b_elf_half e_ehsize; /* ELF header size in bytes */ + b_elf_half e_phentsize; /* Program header table entry size */ + b_elf_half e_phnum; /* Program header table entry count */ + b_elf_half e_shentsize; /* Section header table entry size */ + b_elf_half e_shnum; /* Section header table entry count */ + b_elf_half e_shstrndx; /* Section header string table index */ +} b_elf_ehdr; /* Elf_Ehdr. */ + +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 + +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + +#define EV_CURRENT 1 + +#define ET_DYN 3 + +typedef struct { + b_elf_word sh_name; /* Section name, index in string tbl */ + b_elf_word sh_type; /* Type of section */ + b_elf_wxword sh_flags; /* Miscellaneous section attributes */ + b_elf_addr sh_addr; /* Section virtual addr at execution */ + b_elf_off sh_offset; /* Section file offset */ + b_elf_wxword sh_size; /* Size of section in bytes */ + b_elf_word sh_link; /* Index of another section */ + b_elf_word sh_info; /* Additional section information */ + b_elf_wxword sh_addralign; /* Section alignment */ + b_elf_wxword sh_entsize; /* Entry size if section holds table */ +} b_elf_shdr; /* Elf_Shdr. */ + +#define SHN_UNDEF 0x0000 /* Undefined section */ +#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ +#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */ + +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_DYNSYM 11 + +#if BACKTRACE_ELF_SIZE == 32 + +typedef struct +{ + b_elf_word st_name; /* Symbol name, index in string tbl */ + b_elf_addr st_value; /* Symbol value */ + b_elf_word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol binding and type */ + unsigned char st_other; /* Visibility and other data */ + b_elf_half st_shndx; /* Symbol section index */ +} b_elf_sym; /* Elf_Sym. */ + +#else /* BACKTRACE_ELF_SIZE != 32 */ + +typedef struct +{ + b_elf_word st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Symbol binding and type */ + unsigned char st_other; /* Visibility and other data */ + b_elf_half st_shndx; /* Symbol section index */ + b_elf_addr st_value; /* Symbol value */ + b_elf_xword st_size; /* Symbol size */ +} b_elf_sym; /* Elf_Sym. */ + +#endif /* BACKTRACE_ELF_SIZE != 32 */ + +#define STT_OBJECT 1 +#define STT_FUNC 2 + +/* An index of ELF sections we care about. */ + +enum debug_section +{ + DEBUG_INFO, + DEBUG_LINE, + DEBUG_ABBREV, + DEBUG_RANGES, + DEBUG_STR, + DEBUG_MAX +}; + +/* Names of sections, indexed by enum elf_section. */ + +static const char * const debug_section_names[DEBUG_MAX] = +{ + ".debug_info", + ".debug_line", + ".debug_abbrev", + ".debug_ranges", + ".debug_str" +}; + +/* Information we gather for the sections we care about. */ + +struct debug_section_info +{ + /* Section file offset. */ + off_t offset; + /* Section size. */ + size_t size; + /* Section contents, after read from file. */ + const unsigned char *data; +}; + +/* Information we keep for an ELF symbol. */ + +struct elf_symbol +{ + /* The name of the symbol. */ + const char *name; + /* The address of the symbol. */ + uintptr_t address; + /* The size of the symbol. */ + size_t size; +}; + +/* Information to pass to elf_syminfo. */ + +struct elf_syminfo_data +{ + /* Symbols for the next module. */ + struct elf_syminfo_data *next; + /* The ELF symbols, sorted by address. */ + struct elf_symbol *symbols; + /* The number of symbols. */ + size_t count; +}; + +/* A dummy callback function used when we can't find any debug info. */ + +static int +elf_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, + uintptr_t pc ATTRIBUTE_UNUSED, + backtrace_full_callback callback ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, void *data) +{ + error_callback (data, "no debug info in ELF executable", -1); + return 0; +} + +/* A dummy callback function used when we can't find a symbol + table. */ + +static void +elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, + uintptr_t addr ATTRIBUTE_UNUSED, + backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, void *data) +{ + error_callback (data, "no symbol table in ELF executable", -1); +} + +/* Compare struct elf_symbol for qsort. */ + +static int +elf_symbol_compare (const void *v1, const void *v2) +{ + const struct elf_symbol *e1 = (const struct elf_symbol *) v1; + const struct elf_symbol *e2 = (const struct elf_symbol *) v2; + + if (e1->address < e2->address) + return -1; + else if (e1->address > e2->address) + return 1; + else + return 0; +} + +/* Compare an ADDR against an elf_symbol for bsearch. We allocate one + extra entry in the array so that this can look safely at the next + entry. */ + +static int +elf_symbol_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct elf_symbol *entry = (const struct elf_symbol *) ventry; + uintptr_t addr; + + addr = *key; + if (addr < entry->address) + return -1; + else if (addr >= entry->address + entry->size) + return 1; + else + return 0; +} + +/* Initialize the symbol table info for elf_syminfo. */ + +static int +elf_initialize_syminfo (struct backtrace_state *state, + uintptr_t base_address, + const unsigned char *symtab_data, size_t symtab_size, + const unsigned char *strtab, size_t strtab_size, + backtrace_error_callback error_callback, + void *data, struct elf_syminfo_data *sdata) +{ + size_t sym_count; + const b_elf_sym *sym; + size_t elf_symbol_count; + size_t elf_symbol_size; + struct elf_symbol *elf_symbols; + size_t i; + unsigned int j; + + sym_count = symtab_size / sizeof (b_elf_sym); + + /* We only care about function symbols. Count them. */ + sym = (const b_elf_sym *) symtab_data; + elf_symbol_count = 0; + for (i = 0; i < sym_count; ++i, ++sym) + { + int info; + + info = sym->st_info & 0xf; + if ((info == STT_FUNC || info == STT_OBJECT) + && sym->st_shndx != SHN_UNDEF) + ++elf_symbol_count; + } + + elf_symbol_size = elf_symbol_count * sizeof (struct elf_symbol); + elf_symbols = ((struct elf_symbol *) + backtrace_alloc (state, elf_symbol_size, error_callback, + data)); + if (elf_symbols == NULL) + return 0; + + sym = (const b_elf_sym *) symtab_data; + j = 0; + for (i = 0; i < sym_count; ++i, ++sym) + { + int info; + + info = sym->st_info & 0xf; + if (info != STT_FUNC && info != STT_OBJECT) + continue; + if (sym->st_shndx == SHN_UNDEF) + continue; + if (sym->st_name >= strtab_size) + { + error_callback (data, "symbol string index out of range", 0); + backtrace_free (state, elf_symbols, elf_symbol_size, error_callback, + data); + return 0; + } + elf_symbols[j].name = (const char *) strtab + sym->st_name; + elf_symbols[j].address = sym->st_value + base_address; + elf_symbols[j].size = sym->st_size; + ++j; + } + + backtrace_qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol), + elf_symbol_compare); + + sdata->next = NULL; + sdata->symbols = elf_symbols; + sdata->count = elf_symbol_count; + + return 1; +} + +/* Add EDATA to the list in STATE. */ + +static void +elf_add_syminfo_data (struct backtrace_state *state, + struct elf_syminfo_data *edata) +{ + if (!state->threaded) + { + struct elf_syminfo_data **pp; + + for (pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; + *pp != NULL; + pp = &(*pp)->next) + ; + *pp = edata; + } + else + { + while (1) + { + struct elf_syminfo_data **pp; + + pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; + + while (1) + { + struct elf_syminfo_data *p; + + p = backtrace_atomic_load_pointer (pp); + + if (p == NULL) + break; + + pp = &p->next; + } + + if (__sync_bool_compare_and_swap (pp, NULL, edata)) + break; + } + } +} + +/* Return the symbol name and value for an ADDR. */ + +static void +elf_syminfo (struct backtrace_state *state, uintptr_t addr, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data) +{ + struct elf_syminfo_data *edata; + struct elf_symbol *sym = NULL; + + if (!state->threaded) + { + for (edata = (struct elf_syminfo_data *) state->syminfo_data; + edata != NULL; + edata = edata->next) + { + sym = ((struct elf_symbol *) + bsearch (&addr, edata->symbols, edata->count, + sizeof (struct elf_symbol), elf_symbol_search)); + if (sym != NULL) + break; + } + } + else + { + struct elf_syminfo_data **pp; + + pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; + while (1) + { + edata = backtrace_atomic_load_pointer (pp); + if (edata == NULL) + break; + + sym = ((struct elf_symbol *) + bsearch (&addr, edata->symbols, edata->count, + sizeof (struct elf_symbol), elf_symbol_search)); + if (sym != NULL) + break; + + pp = &edata->next; + } + } + + if (sym == NULL) + callback (data, addr, NULL, 0, 0); + else + callback (data, addr, sym->name, sym->address, sym->size); +} + +/* Add the backtrace data for one ELF file. Returns 1 on success, + 0 on failure (in both cases descriptor is closed) or -1 if exe + is non-zero and the ELF file is ET_DYN, which tells the caller that + elf_add will need to be called on the descriptor again after + base_address is determined. */ + +static int +elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address, + backtrace_error_callback error_callback, void *data, + fileline *fileline_fn, int *found_sym, int *found_dwarf, int exe) +{ + struct backtrace_view ehdr_view; + b_elf_ehdr ehdr; + off_t shoff; + unsigned int shnum; + unsigned int shstrndx; + struct backtrace_view shdrs_view; + int shdrs_view_valid; + const b_elf_shdr *shdrs; + const b_elf_shdr *shstrhdr; + size_t shstr_size; + off_t shstr_off; + struct backtrace_view names_view; + int names_view_valid; + const char *names; + unsigned int symtab_shndx; + unsigned int dynsym_shndx; + unsigned int i; + struct debug_section_info sections[DEBUG_MAX]; + struct backtrace_view symtab_view; + int symtab_view_valid; + struct backtrace_view strtab_view; + int strtab_view_valid; + off_t min_offset; + off_t max_offset; + struct backtrace_view debug_view; + int debug_view_valid; + + *found_sym = 0; + *found_dwarf = 0; + + shdrs_view_valid = 0; + names_view_valid = 0; + symtab_view_valid = 0; + strtab_view_valid = 0; + debug_view_valid = 0; + + if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback, + data, &ehdr_view)) + goto fail; + + memcpy (&ehdr, ehdr_view.data, sizeof ehdr); + + backtrace_release_view (state, &ehdr_view, error_callback, data); + + if (ehdr.e_ident[EI_MAG0] != ELFMAG0 + || ehdr.e_ident[EI_MAG1] != ELFMAG1 + || ehdr.e_ident[EI_MAG2] != ELFMAG2 + || ehdr.e_ident[EI_MAG3] != ELFMAG3) + { + error_callback (data, "executable file is not ELF", 0); + goto fail; + } + if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) + { + error_callback (data, "executable file is unrecognized ELF version", 0); + goto fail; + } + +#if BACKTRACE_ELF_SIZE == 32 +#define BACKTRACE_ELFCLASS ELFCLASS32 +#else +#define BACKTRACE_ELFCLASS ELFCLASS64 +#endif + + if (ehdr.e_ident[EI_CLASS] != BACKTRACE_ELFCLASS) + { + error_callback (data, "executable file is unexpected ELF class", 0); + goto fail; + } + + if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB + && ehdr.e_ident[EI_DATA] != ELFDATA2MSB) + { + error_callback (data, "executable file has unknown endianness", 0); + goto fail; + } + + /* If the executable is ET_DYN, it is either a PIE, or we are running + directly a shared library with .interp. We need to wait for + dl_iterate_phdr in that case to determine the actual base_address. */ + if (exe && ehdr.e_type == ET_DYN) + return -1; + + shoff = ehdr.e_shoff; + shnum = ehdr.e_shnum; + shstrndx = ehdr.e_shstrndx; + + if ((shnum == 0 || shstrndx == SHN_XINDEX) + && shoff != 0) + { + struct backtrace_view shdr_view; + const b_elf_shdr *shdr; + + if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr, + error_callback, data, &shdr_view)) + goto fail; + + shdr = (const b_elf_shdr *) shdr_view.data; + + if (shnum == 0) + shnum = shdr->sh_size; + + if (shstrndx == SHN_XINDEX) + { + shstrndx = shdr->sh_link; + + /* Versions of the GNU binutils between 2.12 and 2.18 did + not handle objects with more than SHN_LORESERVE sections + correctly. All large section indexes were offset by + 0x100. There is more information at + http://sourceware.org/bugzilla/show_bug.cgi?id-5900 . + Fortunately these object files are easy to detect, as the + GNU binutils always put the section header string table + near the end of the list of sections. Thus if the + section header string table index is larger than the + number of sections, then we know we have to subtract + 0x100 to get the real section index. */ + if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100) + shstrndx -= 0x100; + } + + backtrace_release_view (state, &shdr_view, error_callback, data); + } + + /* To translate PC to file/line when using DWARF, we need to find + the .debug_info and .debug_line sections. */ + + /* Read the section headers, skipping the first one. */ + + if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr), + (shnum - 1) * sizeof (b_elf_shdr), + error_callback, data, &shdrs_view)) + goto fail; + shdrs_view_valid = 1; + shdrs = (const b_elf_shdr *) shdrs_view.data; + + /* Read the section names. */ + + shstrhdr = &shdrs[shstrndx - 1]; + shstr_size = shstrhdr->sh_size; + shstr_off = shstrhdr->sh_offset; + + if (!backtrace_get_view (state, descriptor, shstr_off, shstr_size, + error_callback, data, &names_view)) + goto fail; + names_view_valid = 1; + names = (const char *) names_view.data; + + symtab_shndx = 0; + dynsym_shndx = 0; + + memset (sections, 0, sizeof sections); + + /* Look for the symbol table. */ + for (i = 1; i < shnum; ++i) + { + const b_elf_shdr *shdr; + unsigned int sh_name; + const char *name; + int j; + + shdr = &shdrs[i - 1]; + + if (shdr->sh_type == SHT_SYMTAB) + symtab_shndx = i; + else if (shdr->sh_type == SHT_DYNSYM) + dynsym_shndx = i; + + sh_name = shdr->sh_name; + if (sh_name >= shstr_size) + { + error_callback (data, "ELF section name out of range", 0); + goto fail; + } + + name = names + sh_name; + + for (j = 0; j < (int) DEBUG_MAX; ++j) + { + if (strcmp (name, debug_section_names[j]) == 0) + { + sections[j].offset = shdr->sh_offset; + sections[j].size = shdr->sh_size; + break; + } + } + } + + if (symtab_shndx == 0) + symtab_shndx = dynsym_shndx; + if (symtab_shndx != 0) + { + const b_elf_shdr *symtab_shdr; + unsigned int strtab_shndx; + const b_elf_shdr *strtab_shdr; + struct elf_syminfo_data *sdata; + + symtab_shdr = &shdrs[symtab_shndx - 1]; + strtab_shndx = symtab_shdr->sh_link; + if (strtab_shndx >= shnum) + { + error_callback (data, + "ELF symbol table strtab link out of range", 0); + goto fail; + } + strtab_shdr = &shdrs[strtab_shndx - 1]; + + if (!backtrace_get_view (state, descriptor, symtab_shdr->sh_offset, + symtab_shdr->sh_size, error_callback, data, + &symtab_view)) + goto fail; + symtab_view_valid = 1; + + if (!backtrace_get_view (state, descriptor, strtab_shdr->sh_offset, + strtab_shdr->sh_size, error_callback, data, + &strtab_view)) + goto fail; + strtab_view_valid = 1; + + sdata = ((struct elf_syminfo_data *) + backtrace_alloc (state, sizeof *sdata, error_callback, data)); + if (sdata == NULL) + goto fail; + + if (!elf_initialize_syminfo (state, base_address, + symtab_view.data, symtab_shdr->sh_size, + strtab_view.data, strtab_shdr->sh_size, + error_callback, data, sdata)) + { + backtrace_free (state, sdata, sizeof *sdata, error_callback, data); + goto fail; + } + + /* We no longer need the symbol table, but we hold on to the + string table permanently. */ + backtrace_release_view (state, &symtab_view, error_callback, data); + + *found_sym = 1; + + elf_add_syminfo_data (state, sdata); + } + + /* FIXME: Need to handle compressed debug sections. */ + + backtrace_release_view (state, &shdrs_view, error_callback, data); + shdrs_view_valid = 0; + backtrace_release_view (state, &names_view, error_callback, data); + names_view_valid = 0; + + /* Read all the debug sections in a single view, since they are + probably adjacent in the file. We never release this view. */ + + min_offset = 0; + max_offset = 0; + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + off_t end; + + if (sections[i].size == 0) + continue; + if (min_offset == 0 || sections[i].offset < min_offset) + min_offset = sections[i].offset; + end = sections[i].offset + sections[i].size; + if (end > max_offset) + max_offset = end; + } + if (min_offset == 0 || max_offset == 0) + { + if (!backtrace_close (descriptor, error_callback, data)) + goto fail; + return 1; + } + + if (!backtrace_get_view (state, descriptor, min_offset, + max_offset - min_offset, + error_callback, data, &debug_view)) + goto fail; + debug_view_valid = 1; + + /* We've read all we need from the executable. */ + if (!backtrace_close (descriptor, error_callback, data)) + goto fail; + descriptor = -1; + + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + if (sections[i].size == 0) + sections[i].data = NULL; + else + sections[i].data = ((const unsigned char *) debug_view.data + + (sections[i].offset - min_offset)); + } + + if (!backtrace_dwarf_add (state, base_address, + sections[DEBUG_INFO].data, + sections[DEBUG_INFO].size, + sections[DEBUG_LINE].data, + sections[DEBUG_LINE].size, + sections[DEBUG_ABBREV].data, + sections[DEBUG_ABBREV].size, + sections[DEBUG_RANGES].data, + sections[DEBUG_RANGES].size, + sections[DEBUG_STR].data, + sections[DEBUG_STR].size, + ehdr.e_ident[EI_DATA] == ELFDATA2MSB, + error_callback, data, fileline_fn)) + goto fail; + + *found_dwarf = 1; + + return 1; + + fail: + if (shdrs_view_valid) + backtrace_release_view (state, &shdrs_view, error_callback, data); + if (names_view_valid) + backtrace_release_view (state, &names_view, error_callback, data); + if (symtab_view_valid) + backtrace_release_view (state, &symtab_view, error_callback, data); + if (strtab_view_valid) + backtrace_release_view (state, &strtab_view, error_callback, data); + if (debug_view_valid) + backtrace_release_view (state, &debug_view, error_callback, data); + if (descriptor != -1) + backtrace_close (descriptor, error_callback, data); + return 0; +} + +/* Data passed to phdr_callback. */ + +struct phdr_data +{ + struct backtrace_state *state; + backtrace_error_callback error_callback; + void *data; + fileline *fileline_fn; + int *found_sym; + int *found_dwarf; + int exe_descriptor; +}; + +/* Callback passed to dl_iterate_phdr. Load debug info from shared + libraries. */ + +static int +#ifdef __i386__ +__attribute__ ((__force_align_arg_pointer__)) +#endif +phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED, + void *pdata) +{ + struct phdr_data *pd = (struct phdr_data *) pdata; + int descriptor; + int does_not_exist; + fileline elf_fileline_fn; + int found_dwarf; + + /* There is not much we can do if we don't have the module name, + unless executable is ET_DYN, where we expect the very first + phdr_callback to be for the PIE. */ + if (info->dlpi_name == NULL || info->dlpi_name[0] == '\0') + { + if (pd->exe_descriptor == -1) + return 0; + descriptor = pd->exe_descriptor; + pd->exe_descriptor = -1; + } + else + { + if (pd->exe_descriptor != -1) + { + backtrace_close (pd->exe_descriptor, pd->error_callback, pd->data); + pd->exe_descriptor = -1; + } + + descriptor = backtrace_open (info->dlpi_name, pd->error_callback, + pd->data, &does_not_exist); + if (descriptor < 0) + return 0; + } + + if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback, + pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf, 0)) + { + if (found_dwarf) + { + *pd->found_dwarf = 1; + *pd->fileline_fn = elf_fileline_fn; + } + } + + return 0; +} + +/* Initialize the backtrace data we need from an ELF executable. At + the ELF level, all we need to do is find the debug info + sections. */ + +int +backtrace_initialize (struct backtrace_state *state, int descriptor, + backtrace_error_callback error_callback, + void *data, fileline *fileline_fn) +{ + int ret; + int found_sym; + int found_dwarf; + fileline elf_fileline_fn = elf_nodebug; + struct phdr_data pd; + + ret = elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn, + &found_sym, &found_dwarf, 1); + if (!ret) + return 0; + + pd.state = state; + pd.error_callback = error_callback; + pd.data = data; + pd.fileline_fn = &elf_fileline_fn; + pd.found_sym = &found_sym; + pd.found_dwarf = &found_dwarf; + pd.exe_descriptor = ret < 0 ? descriptor : -1; + + dl_iterate_phdr (phdr_callback, (void *) &pd); + + if (!state->threaded) + { + if (found_sym) + state->syminfo_fn = elf_syminfo; + else if (state->syminfo_fn == NULL) + state->syminfo_fn = elf_nosyms; + } + else + { + if (found_sym) + backtrace_atomic_store_pointer (&state->syminfo_fn, elf_syminfo); + else + (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, + elf_nosyms); + } + + if (!state->threaded) + { + if (state->fileline_fn == NULL || state->fileline_fn == elf_nodebug) + *fileline_fn = elf_fileline_fn; + } + else + { + fileline current_fn; + + current_fn = backtrace_atomic_load_pointer (&state->fileline_fn); + if (current_fn == NULL || current_fn == elf_nodebug) + *fileline_fn = elf_fileline_fn; + } + + return 1; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/fileline.c b/backtrace-sys-0.1.16/src/libbacktrace/fileline.c new file mode 100644 index 000000000..503bbc6bc --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/fileline.c @@ -0,0 +1,194 @@ +/* fileline.c -- Get file and line number information in a backtrace. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +#ifndef HAVE_GETEXECNAME +#define getexecname() NULL +#endif + +/* Initialize the fileline information from the executable. Returns 1 + on success, 0 on failure. */ + +static int +fileline_initialize (struct backtrace_state *state, + backtrace_error_callback error_callback, void *data) +{ + int failed; + fileline fileline_fn; + int pass; + int called_error_callback; + int descriptor; + + if (!state->threaded) + failed = state->fileline_initialization_failed; + else + failed = backtrace_atomic_load_int (&state->fileline_initialization_failed); + + if (failed) + { + error_callback (data, "failed to read executable information", -1); + return 0; + } + + if (!state->threaded) + fileline_fn = state->fileline_fn; + else + fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); + if (fileline_fn != NULL) + return 1; + + /* We have not initialized the information. Do it now. */ + + descriptor = -1; + called_error_callback = 0; + for (pass = 0; pass < 4; ++pass) + { + const char *filename; + int does_not_exist; + + switch (pass) + { + case 0: + filename = state->filename; + break; + case 1: + filename = getexecname (); + break; + case 2: + filename = "/proc/self/exe"; + break; + case 3: + filename = "/proc/curproc/file"; + break; + default: + abort (); + } + + if (filename == NULL) + continue; + + descriptor = backtrace_open (filename, error_callback, data, + &does_not_exist); + if (descriptor < 0 && !does_not_exist) + { + called_error_callback = 1; + break; + } + if (descriptor >= 0) + break; + } + + if (descriptor < 0) + { + if (!called_error_callback) + { + if (state->filename != NULL) + error_callback (data, state->filename, ENOENT); + else + error_callback (data, + "libbacktrace could not find executable to open", + 0); + } + failed = 1; + } + + if (!failed) + { + if (!backtrace_initialize (state, descriptor, error_callback, data, + &fileline_fn)) + failed = 1; + } + + if (failed) + { + if (!state->threaded) + state->fileline_initialization_failed = 1; + else + backtrace_atomic_store_int (&state->fileline_initialization_failed, 1); + return 0; + } + + if (!state->threaded) + state->fileline_fn = fileline_fn; + else + { + backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn); + + /* Note that if two threads initialize at once, one of the data + sets may be leaked. */ + } + + return 1; +} + +/* Given a PC, find the file name, line number, and function name. */ + +int +backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc, + backtrace_full_callback callback, + backtrace_error_callback error_callback, void *data) +{ + if (!fileline_initialize (state, error_callback, data)) + return 0; + + if (state->fileline_initialization_failed) + return 0; + + return state->fileline_fn (state, pc, callback, error_callback, data); +} + +/* Given a PC, find the symbol for it, and its value. */ + +int +backtrace_syminfo (struct backtrace_state *state, uintptr_t pc, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback, void *data) +{ + if (!fileline_initialize (state, error_callback, data)) + return 0; + + if (state->fileline_initialization_failed) + return 0; + + state->syminfo_fn (state, pc, callback, error_callback, data); + return 1; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/filenames.h b/backtrace-sys-0.1.16/src/libbacktrace/filenames.h new file mode 100644 index 000000000..1161daaa4 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/filenames.h @@ -0,0 +1,99 @@ +/* Macros for taking apart, interpreting and processing file names. + + These are here because some non-Posix (a.k.a. DOSish) systems have + drive letter brain-damage at the beginning of an absolute file name, + use forward- and back-slash in path names interchangeably, and + some of them have case-insensitive file names. + + Copyright (C) 2000-2015 Free Software Foundation, Inc. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef FILENAMES_H +#define FILENAMES_H + +#include "hashtab.h" /* for hashval_t */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__) || defined (__CYGWIN__) +# ifndef HAVE_DOS_BASED_FILE_SYSTEM +# define HAVE_DOS_BASED_FILE_SYSTEM 1 +# endif +# ifndef HAVE_CASE_INSENSITIVE_FILE_SYSTEM +# define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1 +# endif +# define HAS_DRIVE_SPEC(f) HAS_DOS_DRIVE_SPEC (f) +# define IS_DIR_SEPARATOR(c) IS_DOS_DIR_SEPARATOR (c) +# define IS_ABSOLUTE_PATH(f) IS_DOS_ABSOLUTE_PATH (f) +#else /* not DOSish */ +# if defined(__APPLE__) +# ifndef HAVE_CASE_INSENSITIVE_FILE_SYSTEM +# define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1 +# endif +# endif /* __APPLE__ */ +# define HAS_DRIVE_SPEC(f) (0) +# define IS_DIR_SEPARATOR(c) IS_UNIX_DIR_SEPARATOR (c) +# define IS_ABSOLUTE_PATH(f) IS_UNIX_ABSOLUTE_PATH (f) +#endif + +#define IS_DIR_SEPARATOR_1(dos_based, c) \ + (((c) == '/') \ + || (((c) == '\\') && (dos_based))) + +#define HAS_DRIVE_SPEC_1(dos_based, f) \ + ((f)[0] && ((f)[1] == ':') && (dos_based)) + +/* Remove the drive spec from F, assuming HAS_DRIVE_SPEC (f). + The result is a pointer to the remainder of F. */ +#define STRIP_DRIVE_SPEC(f) ((f) + 2) + +#define IS_DOS_DIR_SEPARATOR(c) IS_DIR_SEPARATOR_1 (1, c) +#define IS_DOS_ABSOLUTE_PATH(f) IS_ABSOLUTE_PATH_1 (1, f) +#define HAS_DOS_DRIVE_SPEC(f) HAS_DRIVE_SPEC_1 (1, f) + +#define IS_UNIX_DIR_SEPARATOR(c) IS_DIR_SEPARATOR_1 (0, c) +#define IS_UNIX_ABSOLUTE_PATH(f) IS_ABSOLUTE_PATH_1 (0, f) + +/* Note that when DOS_BASED is true, IS_ABSOLUTE_PATH accepts d:foo as + well, although it is only semi-absolute. This is because the users + of IS_ABSOLUTE_PATH want to know whether to prepend the current + working directory to a file name, which should not be done with a + name like d:foo. */ +#define IS_ABSOLUTE_PATH_1(dos_based, f) \ + (IS_DIR_SEPARATOR_1 (dos_based, (f)[0]) \ + || HAS_DRIVE_SPEC_1 (dos_based, f)) + +extern int filename_cmp (const char *s1, const char *s2); +#define FILENAME_CMP(s1, s2) filename_cmp(s1, s2) + +extern int filename_ncmp (const char *s1, const char *s2, + size_t n); + +extern hashval_t filename_hash (const void *s); + +extern int filename_eq (const void *s1, const void *s2); + +extern int canonical_filename_eq (const char *a, const char *b); + +#ifdef __cplusplus +} +#endif + +#endif /* FILENAMES_H */ diff --git a/backtrace-sys-0.1.16/src/libbacktrace/filetype.awk b/backtrace-sys-0.1.16/src/libbacktrace/filetype.awk new file mode 100644 index 000000000..57bab797a --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/filetype.awk @@ -0,0 +1,5 @@ +# An awk script to determine the type of a file. +/\177ELF\001/ { if (NR == 1) { print "elf32"; exit } } +/\177ELF\002/ { if (NR == 1) { print "elf64"; exit } } +/\114\001/ { if (NR == 1) { print "pecoff"; exit } } +/\144\206/ { if (NR == 1) { print "pecoff"; exit } } diff --git a/backtrace-sys-0.1.16/src/libbacktrace/hashtab.h b/backtrace-sys-0.1.16/src/libbacktrace/hashtab.h new file mode 100644 index 000000000..b1b5877aa --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/hashtab.h @@ -0,0 +1,204 @@ +/* An expandable hash tables datatype. + Copyright (C) 1999-2015 Free Software Foundation, Inc. + Contributed by Vladimir Makarov (vmakarov@cygnus.com). + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* This package implements basic hash table functionality. It is possible + to search for an entry, create an entry and destroy an entry. + + Elements in the table are generic pointers. + + The size of the table is not fixed; if the occupancy of the table + grows too high the hash table will be expanded. + + The abstract data implementation is based on generalized Algorithm D + from Knuth's book "The art of computer programming". Hash table is + expanded by creation of new hash table and transferring elements from + the old table to the new table. */ + +#ifndef __HASHTAB_H__ +#define __HASHTAB_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "ansidecl.h" + +/* The type for a hash code. */ +typedef unsigned int hashval_t; + +/* Callback function pointer types. */ + +/* Calculate hash of a table entry. */ +typedef hashval_t (*htab_hash) (const void *); + +/* Compare a table entry with a possible entry. The entry already in + the table always comes first, so the second element can be of a + different type (but in this case htab_find and htab_find_slot + cannot be used; instead the variants that accept a hash value + must be used). */ +typedef int (*htab_eq) (const void *, const void *); + +/* Cleanup function called whenever a live element is removed from + the hash table. */ +typedef void (*htab_del) (void *); + +/* Function called by htab_traverse for each live element. The first + arg is the slot of the element (which can be passed to htab_clear_slot + if desired), the second arg is the auxiliary pointer handed to + htab_traverse. Return 1 to continue scan, 0 to stop. */ +typedef int (*htab_trav) (void **, void *); + +/* Memory-allocation function, with the same functionality as calloc(). + Iff it returns NULL, the hash table implementation will pass an error + code back to the user, so if your code doesn't handle errors, + best if you use xcalloc instead. */ +typedef void *(*htab_alloc) (size_t, size_t); + +/* We also need a free() routine. */ +typedef void (*htab_free) (void *); + +/* Memory allocation and deallocation; variants which take an extra + argument. */ +typedef void *(*htab_alloc_with_arg) (void *, size_t, size_t); +typedef void (*htab_free_with_arg) (void *, void *); + +/* This macro defines reserved value for empty table entry. */ + +#define HTAB_EMPTY_ENTRY ((PTR) 0) + +/* This macro defines reserved value for table entry which contained + a deleted element. */ + +#define HTAB_DELETED_ENTRY ((PTR) 1) + +/* Hash tables are of the following type. The structure + (implementation) of this type is not needed for using the hash + tables. All work with hash table should be executed only through + functions mentioned below. The size of this structure is subject to + change. */ + +struct htab { + /* Pointer to hash function. */ + htab_hash hash_f; + + /* Pointer to comparison function. */ + htab_eq eq_f; + + /* Pointer to cleanup function. */ + htab_del del_f; + + /* Table itself. */ + void **entries; + + /* Current size (in entries) of the hash table. */ + size_t size; + + /* Current number of elements including also deleted elements. */ + size_t n_elements; + + /* Current number of deleted elements in the table. */ + size_t n_deleted; + + /* The following member is used for debugging. Its value is number + of all calls of `htab_find_slot' for the hash table. */ + unsigned int searches; + + /* The following member is used for debugging. Its value is number + of collisions fixed for time of work with the hash table. */ + unsigned int collisions; + + /* Pointers to allocate/free functions. */ + htab_alloc alloc_f; + htab_free free_f; + + /* Alternate allocate/free functions, which take an extra argument. */ + void *alloc_arg; + htab_alloc_with_arg alloc_with_arg_f; + htab_free_with_arg free_with_arg_f; + + /* Current size (in entries) of the hash table, as an index into the + table of primes. */ + unsigned int size_prime_index; +}; + +typedef struct htab *htab_t; + +/* An enum saying whether we insert into the hash table or not. */ +enum insert_option {NO_INSERT, INSERT}; + +/* The prototypes of the package functions. */ + +extern htab_t htab_create_alloc (size_t, htab_hash, + htab_eq, htab_del, + htab_alloc, htab_free); + +extern htab_t htab_create_alloc_ex (size_t, htab_hash, + htab_eq, htab_del, + void *, htab_alloc_with_arg, + htab_free_with_arg); + +extern htab_t htab_create_typed_alloc (size_t, htab_hash, htab_eq, htab_del, + htab_alloc, htab_alloc, htab_free); + +/* Backward-compatibility functions. */ +extern htab_t htab_create (size_t, htab_hash, htab_eq, htab_del); +extern htab_t htab_try_create (size_t, htab_hash, htab_eq, htab_del); + +extern void htab_set_functions_ex (htab_t, htab_hash, + htab_eq, htab_del, + void *, htab_alloc_with_arg, + htab_free_with_arg); + +extern void htab_delete (htab_t); +extern void htab_empty (htab_t); + +extern void * htab_find (htab_t, const void *); +extern void ** htab_find_slot (htab_t, const void *, enum insert_option); +extern void * htab_find_with_hash (htab_t, const void *, hashval_t); +extern void ** htab_find_slot_with_hash (htab_t, const void *, + hashval_t, enum insert_option); +extern void htab_clear_slot (htab_t, void **); +extern void htab_remove_elt (htab_t, void *); +extern void htab_remove_elt_with_hash (htab_t, void *, hashval_t); + +extern void htab_traverse (htab_t, htab_trav, void *); +extern void htab_traverse_noresize (htab_t, htab_trav, void *); + +extern size_t htab_size (htab_t); +extern size_t htab_elements (htab_t); +extern double htab_collisions (htab_t); + +/* A hash function for pointers. */ +extern htab_hash htab_hash_pointer; + +/* An equality function for pointers. */ +extern htab_eq htab_eq_pointer; + +/* A hash function for null-terminated strings. */ +extern hashval_t htab_hash_string (const void *); + +/* An iterative hash function for arbitrary data. */ +extern hashval_t iterative_hash (const void *, size_t, hashval_t); +/* Shorthand for hashing something with an intrinsic size. */ +#define iterative_hash_object(OB,INIT) iterative_hash (&OB, sizeof (OB), INIT) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __HASHTAB_H */ diff --git a/backtrace-sys-0.1.16/src/libbacktrace/install-sh b/backtrace-sys-0.1.16/src/libbacktrace/install-sh new file mode 100755 index 000000000..0b0fdcbba --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/install-sh @@ -0,0 +1,501 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2013-12-25.23; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# 'make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +tab=' ' +nl=' +' +IFS=" $tab$nl" + +# Set DOITPROG to "echo" to test this script. + +doit=${DOITPROG-} +doit_exec=${doit:-exec} + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +is_target_a_directory=possibly + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) + is_target_a_directory=always + dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) is_target_a_directory=never;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +# We allow the use of options -d and -T together, by making -d +# take the precedence; this is for compatibility with GNU install. + +if test -n "$dir_arg"; then + if test -n "$dst_arg"; then + echo "$0: target directory not allowed when installing a directory." >&2 + exit 1 + fi +fi + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + if test $# -gt 1 || test "$is_target_a_directory" = always; then + if test ! -d "$dst_arg"; then + echo "$0: $dst_arg: Is not a directory." >&2 + exit 1 + fi + fi +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test "$is_target_a_directory" = never; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + dstdir=`dirname "$dst"` + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + oIFS=$IFS + IFS=/ + set -f + set fnord $dstdir + shift + set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + set +f && + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/backtrace-sys-0.1.16/src/libbacktrace/internal.h b/backtrace-sys-0.1.16/src/libbacktrace/internal.h new file mode 100644 index 000000000..aab4e2a00 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/internal.h @@ -0,0 +1,294 @@ +/* internal.h -- Internal header file for stack backtrace library. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#ifndef BACKTRACE_INTERNAL_H +#define BACKTRACE_INTERNAL_H + +/* We assume that and "backtrace.h" have already been + included. */ + +#ifndef GCC_VERSION +# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +#endif + +#if (GCC_VERSION < 2007) +# define __attribute__(x) +#endif + +#ifndef ATTRIBUTE_UNUSED +# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif + +#ifndef ATTRIBUTE_MALLOC +# if (GCC_VERSION >= 2096) +# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) +# else +# define ATTRIBUTE_MALLOC +# endif +#endif + +#ifndef HAVE_SYNC_FUNCTIONS + +/* Define out the sync functions. These should never be called if + they are not available. */ + +#define __sync_bool_compare_and_swap(A, B, C) (abort(), 1) +#define __sync_lock_test_and_set(A, B) (abort(), 0) +#define __sync_lock_release(A) abort() + +#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ + +#ifdef HAVE_ATOMIC_FUNCTIONS + +/* We have the atomic builtin functions. */ + +#define backtrace_atomic_load_pointer(p) \ + __atomic_load_n ((p), __ATOMIC_ACQUIRE) +#define backtrace_atomic_load_int(p) \ + __atomic_load_n ((p), __ATOMIC_ACQUIRE) +#define backtrace_atomic_store_pointer(p, v) \ + __atomic_store_n ((p), (v), __ATOMIC_RELEASE) +#define backtrace_atomic_store_size_t(p, v) \ + __atomic_store_n ((p), (v), __ATOMIC_RELEASE) +#define backtrace_atomic_store_int(p, v) \ + __atomic_store_n ((p), (v), __ATOMIC_RELEASE) + +#else /* !defined (HAVE_ATOMIC_FUNCTIONS) */ +#ifdef HAVE_SYNC_FUNCTIONS + +/* We have the sync functions but not the atomic functions. Define + the atomic ones in terms of the sync ones. */ + +extern void *backtrace_atomic_load_pointer (void *); +extern int backtrace_atomic_load_int (int *); +extern void backtrace_atomic_store_pointer (void *, void *); +extern void backtrace_atomic_store_size_t (size_t *, size_t); +extern void backtrace_atomic_store_int (int *, int); + +#else /* !defined (HAVE_SYNC_FUNCTIONS) */ + +/* We have neither the sync nor the atomic functions. These will + never be called. */ + +#define backtrace_atomic_load_pointer(p) (abort(), (void *) NULL) +#define backtrace_atomic_load_int(p) (abort(), 0) +#define backtrace_atomic_store_pointer(p, v) abort() +#define backtrace_atomic_store_size_t(p, v) abort() +#define backtrace_atomic_store_int(p, v) abort() + +#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ +#endif /* !defined (HAVE_ATOMIC_FUNCTIONS) */ + +/* The type of the function that collects file/line information. This + is like backtrace_pcinfo. */ + +typedef int (*fileline) (struct backtrace_state *state, uintptr_t pc, + backtrace_full_callback callback, + backtrace_error_callback error_callback, void *data); + +/* The type of the function that collects symbol information. This is + like backtrace_syminfo. */ + +typedef void (*syminfo) (struct backtrace_state *state, uintptr_t pc, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback, void *data); + +/* What the backtrace state pointer points to. */ + +struct backtrace_state +{ + /* The name of the executable. */ + const char *filename; + /* Non-zero if threaded. */ + int threaded; + /* The master lock for fileline_fn, fileline_data, syminfo_fn, + syminfo_data, fileline_initialization_failed and everything the + data pointers point to. */ + void *lock; + /* The function that returns file/line information. */ + fileline fileline_fn; + /* The data to pass to FILELINE_FN. */ + void *fileline_data; + /* The function that returns symbol information. */ + syminfo syminfo_fn; + /* The data to pass to SYMINFO_FN. */ + void *syminfo_data; + /* Whether initializing the file/line information failed. */ + int fileline_initialization_failed; + /* The lock for the freelist. */ + int lock_alloc; + /* The freelist when using mmap. */ + struct backtrace_freelist_struct *freelist; +}; + +/* Open a file for reading. Returns -1 on error. If DOES_NOT_EXIST + is not NULL, *DOES_NOT_EXIST will be set to 0 normally and set to 1 + if the file does not exist. If the file does not exist and + DOES_NOT_EXIST is not NULL, the function will return -1 and will + not call ERROR_CALLBACK. On other errors, or if DOES_NOT_EXIST is + NULL, the function will call ERROR_CALLBACK before returning. */ +extern int backtrace_open (const char *filename, + backtrace_error_callback error_callback, + void *data, + int *does_not_exist); + +/* A view of the contents of a file. This supports mmap when + available. A view will remain in memory even after backtrace_close + is called on the file descriptor from which the view was + obtained. */ + +struct backtrace_view +{ + /* The data that the caller requested. */ + const void *data; + /* The base of the view. */ + void *base; + /* The total length of the view. */ + size_t len; +}; + +/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. Store the + result in *VIEW. Returns 1 on success, 0 on error. */ +extern int backtrace_get_view (struct backtrace_state *state, int descriptor, + off_t offset, size_t size, + backtrace_error_callback error_callback, + void *data, struct backtrace_view *view); + +/* Release a view created by backtrace_get_view. */ +extern void backtrace_release_view (struct backtrace_state *state, + struct backtrace_view *view, + backtrace_error_callback error_callback, + void *data); + +/* Close a file opened by backtrace_open. Returns 1 on success, 0 on + error. */ + +extern int backtrace_close (int descriptor, + backtrace_error_callback error_callback, + void *data); + +/* Sort without using memory. */ + +extern void backtrace_qsort (void *base, size_t count, size_t size, + int (*compar) (const void *, const void *)); + +/* Allocate memory. This is like malloc. If ERROR_CALLBACK is NULL, + this does not report an error, it just returns NULL. */ + +extern void *backtrace_alloc (struct backtrace_state *state, size_t size, + backtrace_error_callback error_callback, + void *data) ATTRIBUTE_MALLOC; + +/* Free memory allocated by backtrace_alloc. If ERROR_CALLBACK is + NULL, this does not report an error. */ + +extern void backtrace_free (struct backtrace_state *state, void *mem, + size_t size, + backtrace_error_callback error_callback, + void *data); + +/* A growable vector of some struct. This is used for more efficient + allocation when we don't know the final size of some group of data + that we want to represent as an array. */ + +struct backtrace_vector +{ + /* The base of the vector. */ + void *base; + /* The number of bytes in the vector. */ + size_t size; + /* The number of bytes available at the current allocation. */ + size_t alc; +}; + +/* Grow VEC by SIZE bytes. Return a pointer to the newly allocated + bytes. Note that this may move the entire vector to a new memory + location. Returns NULL on failure. */ + +extern void *backtrace_vector_grow (struct backtrace_state *state, size_t size, + backtrace_error_callback error_callback, + void *data, + struct backtrace_vector *vec); + +/* Finish the current allocation on VEC. Prepare to start a new + allocation. The finished allocation will never be freed. Returns + a pointer to the base of the finished entries, or NULL on + failure. */ + +extern void* backtrace_vector_finish (struct backtrace_state *state, + struct backtrace_vector *vec, + backtrace_error_callback error_callback, + void *data); + +/* Release any extra space allocated for VEC. This may change + VEC->base. Returns 1 on success, 0 on failure. */ + +extern int backtrace_vector_release (struct backtrace_state *state, + struct backtrace_vector *vec, + backtrace_error_callback error_callback, + void *data); + +/* Read initial debug data from a descriptor, and set the + fileline_data, syminfo_fn, and syminfo_data fields of STATE. + Return the fileln_fn field in *FILELN_FN--this is done this way so + that the synchronization code is only implemented once. This is + called after the descriptor has first been opened. It will close + the descriptor if it is no longer needed. Returns 1 on success, 0 + on error. There will be multiple implementations of this function, + for different file formats. Each system will compile the + appropriate one. */ + +extern int backtrace_initialize (struct backtrace_state *state, + int descriptor, + backtrace_error_callback error_callback, + void *data, + fileline *fileline_fn); + +/* Add file/line information for a DWARF module. */ + +extern int backtrace_dwarf_add (struct backtrace_state *state, + uintptr_t base_address, + const unsigned char* dwarf_info, + size_t dwarf_info_size, + const unsigned char *dwarf_line, + size_t dwarf_line_size, + const unsigned char *dwarf_abbrev, + size_t dwarf_abbrev_size, + const unsigned char *dwarf_ranges, + size_t dwarf_range_size, + const unsigned char *dwarf_str, + size_t dwarf_str_size, + int is_bigendian, + backtrace_error_callback error_callback, + void *data, fileline *fileline_fn); + +#endif diff --git a/backtrace-sys-0.1.16/src/libbacktrace/ltmain.sh b/backtrace-sys-0.1.16/src/libbacktrace/ltmain.sh new file mode 100644 index 000000000..9503ec85d --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/ltmain.sh @@ -0,0 +1,8636 @@ +# Generated from ltmain.m4sh. + +# libtool (GNU libtool 1.3134 2009-11-29) 2.2.7a +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008, 2009 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --no-finish let install mode avoid finish commands +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --no-quiet, --no-silent +# print informational messages (default) +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print more informational messages than default +# --no-verbose don't print the extra informational messages +# --version print version information +# -h, --help, --help-all print short, long, or detailed help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. When passed as first option, +# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool 1.3134 2009-11-29) 2.2.7a +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . + +PROGRAM=libtool +PACKAGE=libtool +VERSION=2.2.7a +TIMESTAMP=" 1.3134 2009-11-29" +package_revision=1.3134 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# NLS nuisances: We save the old values to restore during execute mode. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done + +$lt_unset CDPATH + + + + + + + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + + + +: ${CP="cp -f"} +: ${ECHO=$as_echo} +: ${EGREP="/bin/grep -E"} +: ${FGREP="/bin/grep -F"} +: ${GREP="/bin/grep"} +: ${LN_S="ln -s"} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SED="/mount/endor/wildenhu/local-x86_64/bin/sed"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` +} + +# Generated shell functions inserted here. + +# These SED scripts presuppose an absolute path with a trailing slash. +pathcar='s,^/\([^/]*\).*$,\1,' +pathcdr='s,^/[^/]*,,' +removedotparts=':dotsl + s@/\./@/@g + t dotsl + s,/\.$,/,' +collapseslashes='s@/\{1,\}@/@g' +finalslash='s,/*$,/,' + +# func_normal_abspath PATH +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +# value returned in "$func_normal_abspath_result" +func_normal_abspath () +{ + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` + while :; do + # Processed it all yet? + if test "$func_normal_abspath_tpath" = / ; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result" ; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + +# func_relative_path SRCDIR DSTDIR +# generates a relative path from SRCDIR to DSTDIR, with a trailing +# slash if non-empty, suitable for immediately appending a filename +# without needing to append a separator. +# value returned in "$func_relative_path_result" +func_relative_path () +{ + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=${func_dirname_result} + if test "x$func_relative_path_tlibdir" = x ; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test "x$func_stripname_result" != x ; then + func_relative_path_result=${func_relative_path_result}/${func_stripname_result} + fi + + # Normalisation. If bindir is libdir, return empty string, + # else relative path ending with a slash; either way, target + # file name can be directly appended. + if test ! -z "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result/" + func_relative_path_result=$func_stripname_result + fi +} + +# The name of this program: +func_dirname_and_basename "$progpath" +progname=$func_basename_result + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=: + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname${mode+: }$mode: $*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` + done + my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "$my_tmpdir" +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "$1" | $SED \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + + + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $SED -n '/(C)/!b go + :more + /\./!{ + N + s/\n# // + b more + } + :go + /^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $SED -n '/^# Usage:/,/^# *-h/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + echo + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help [NOEXIT] +# Echo long help message to standard output and exit, +# unless 'noexit' is passed as argument. +func_help () +{ + $SED -n '/^# Usage:/,/# Report bugs to/ { + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ + p + }' < "$progpath" + ret=$? + if test -z "$1"; then + exit $ret + fi +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + func_error "missing argument for $1" + exit_cmd=exit +} + +exit_cmd=: + + + + + + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +# $mode is unset +nonopt= +execute_dlfiles= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +opt_dry_run=false +opt_finish=: +opt_duplicate_deps=false +opt_silent=false +opt_debug=: + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +# func_fatal_configuration arg... +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_error ${1+"$@"} + func_error "See the $PACKAGE documentation for more information." + func_fatal_error "Fatal configuration error." +} + + +# func_config +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + +# func_features +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + +# func_enable_tag tagname +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname="$1" + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf="/$re_begincf/,/$re_endcf/p" + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# Parse options once, thoroughly. This comes as soon as possible in +# the script to make things like `libtool --version' happen quickly. +{ + + # Shorthand for --mode=foo, only valid as the first argument + case $1 in + clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; + compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; + execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; + finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; + install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; + link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; + uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; + esac + + # Parse non-mode specific arguments: + while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --config) func_config ;; + + --debug) preserve_args="$preserve_args $opt" + func_echo "enabling shell trace mode" + opt_debug='set -x' + $opt_debug + ;; + + -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break + execute_dlfiles="$execute_dlfiles $1" + shift + ;; + + --dry-run | -n) opt_dry_run=: ;; + --features) func_features ;; + --finish) mode="finish" ;; + --no-finish) opt_finish=false ;; + + --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break + case $1 in + # Valid mode arguments: + clean) ;; + compile) ;; + execute) ;; + finish) ;; + install) ;; + link) ;; + relink) ;; + uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; + esac + + mode="$1" + shift + ;; + + --preserve-dup-deps) + opt_duplicate_deps=: ;; + + --quiet|--silent) preserve_args="$preserve_args $opt" + opt_silent=: + opt_verbose=false + ;; + + --no-quiet|--no-silent) + preserve_args="$preserve_args $opt" + opt_silent=false + ;; + + --verbose| -v) preserve_args="$preserve_args $opt" + opt_silent=false + opt_verbose=: + ;; + + --no-verbose) preserve_args="$preserve_args $opt" + opt_verbose=false + ;; + + --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break + preserve_args="$preserve_args $opt $1" + func_enable_tag "$1" # tagname is set here + shift + ;; + + # Separate optargs to long options: + -dlopen=*|--mode=*|--tag=*) + func_opt_split "$opt" + set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} + shift + ;; + + -\?|-h) func_usage ;; + --help) opt_help=: ;; + --help-all) opt_help=': help-all' ;; + --version) func_version ;; + + -*) func_fatal_help "unrecognized option \`$opt'" ;; + + *) nonopt="$opt" + break + ;; + esac + done + + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* ) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_duplicate_deps + ;; + esac + + # Having warned about all mis-specified options, bail out if + # anything was wrong. + $exit_cmd $EXIT_FAILURE +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +## ----------- ## +## Main. ## +## ----------- ## + +$opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + test -z "$mode" && func_fatal_error "error: you must specify a MODE." + + + # Darwin sucks + eval "std_shrext=\"$shrext_cmds\"" + + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$mode' for more information." +} + + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_ltwrapper_scriptname_result="" + if func_ltwrapper_executable_p "$1"; then + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" + fi +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval "cmd=\"$cmd\"" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_quote_for_eval "$arg" + CC_quoted="$CC_quoted $func_quote_for_eval_result" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T <?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + removelist="$removelist $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + removelist="$removelist $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + if test -n "$fix_srcfile_path"; then + eval "srcfile=\"$fix_srcfile_path\"" + fi + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + command="$command -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test "$mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to building PIC objects only + -prefer-non-pic try to building non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$mode'" + ;; + esac + + echo + $ECHO "Try \`$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test "$opt_help" = :; then + func_mode_help + else + { + func_help noexit + for mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | sed -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + sed '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval test -z \"\$$shlibpath_var\"; then + eval $shlibpath_var=\$dir + else + eval $shlibpath_var=\$dir:\$$shlibpath_var + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_quote_for_eval "$file" + args="$args $func_quote_for_eval_result" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval "flag=\"$hardcode_libdir_flag_spec\"" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + exit $EXIT_SUCCESS +} + +test "$mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + install_prog="$install_prog$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + files="$files $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test "x$prev" = x-m && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + install_prog="$install_prog $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + install_shared_prog="$install_shared_prog $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + install_shared_prog="$install_shared_prog -m $func_quote_for_eval_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + dir="$dir$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs" && $opt_finish; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_verbose "extracting global C symbols from \`$progfile'" + $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + $EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + ${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' < "$nlist" > "$export_symbols" + case $host in + *cygwin* | *mingw* | *cegcc* ) + echo EXPORTS > "$output_objdir/$outputname.def" + cat "$export_symbols" >> "$output_objdir/$outputname.def" + ;; + esac + } + else + $opt_dry_run || { + ${SED} -e 's/\([].[*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/' < "$export_symbols" > "$output_objdir/$outputname.exp" + $GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + case $host in + *cygwin* | *mingw* | *cegcc* ) + echo EXPORTS > "$output_objdir/$outputname.def" + cat "$nlist" >> "$output_objdir/$outputname.def" + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + $opt_dry_run || { + $ECHO ": $name " >> "$nlist" + eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +" + case $host in + *cygwin* | *mingw* | *cegcc* ) + echo >> "$output_objdir/$my_dlsyms" "\ +/* DATA imports from DLLs on WIN32 con't be const, because + runtime relocations are performed -- see ld's documentation + on pseudo-relocs. */" + lt_dlsym_const= ;; + *osf5*) + echo >> "$output_objdir/$my_dlsyms" "\ +/* This system does not cope well with relocations in const data */" + lt_dlsym_const= ;; + *) + lt_dlsym_const=const ;; + esac + + echo >> "$output_objdir/$my_dlsyms" "\ +extern $lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +$lt_dlsym_const lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) symtab_cflags="$symtab_cflags $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + if $OBJDUMP -f "$1" | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pe-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + win32_nmres=`$NM -f posix -A "$1" | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + if test "$lock_old_archive_extraction" = yes; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test "$lock_old_archive_extraction" = yes; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi\ + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \"\$relink_command\" 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_to_host_path arg +# +# Convert paths to host format when used with build tools. +# Intended for use with "native" mingw (where libtool itself +# is running under the msys shell), or in the following cross- +# build environments: +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# where wine is equipped with the `winepath' executable. +# In the native mingw case, the (msys) shell automatically +# converts paths for any non-msys applications it launches, +# but that facility isn't available from inside the cwrapper. +# Similar accommodations are necessary for $host mingw and +# $build cygwin. Calling this function does no harm for other +# $host/$build combinations not listed above. +# +# ARG is the path (on $build) that should be converted to +# the proper representation for $host. The result is stored +# in $func_to_host_path_result. +func_to_host_path () +{ + func_to_host_path_result="$1" + if test -n "$1"; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + case $build in + *mingw* ) # actually, msys + # awkward: cmd appends spaces to result + func_to_host_path_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_path_result=`cygpath -w "$1" | + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # Unfortunately, winepath does not exit with a non-zero + # error code, so we are forced to check the contents of + # stdout. On the other hand, if the command is not + # found, the shell will set an exit code of 127 and print + # *an error message* to stdout. So we must check for both + # error code of zero AND non-empty stdout, which explains + # the odd construction: + func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` + if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then + func_to_host_path_result=`$ECHO "$func_to_host_path_tmp1" | + $SED -e "$lt_sed_naive_backslashify"` + else + # Allow warning below. + func_to_host_path_result= + fi + ;; + esac + if test -z "$func_to_host_path_result" ; then + func_error "Could not determine host path corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_path_result="$1" + fi + ;; + esac + fi +} +# end: func_to_host_path + +# func_to_host_pathlist arg +# +# Convert pathlists to host format when used with build tools. +# See func_to_host_path(), above. This function supports the +# following $build/$host combinations (but does no harm for +# combinations not listed here): +# $build $host +# mingw (msys) mingw [e.g. native] +# cygwin mingw +# *nix + wine mingw +# +# Path separators are also converted from $build format to +# $host format. If ARG begins or ends with a path separator +# character, it is preserved (but converted to $host format) +# on output. +# +# ARG is a pathlist (on $build) that should be converted to +# the proper representation on $host. The result is stored +# in $func_to_host_pathlist_result. +func_to_host_pathlist () +{ + func_to_host_pathlist_result="$1" + if test -n "$1"; then + case $host in + *mingw* ) + lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_pathlist_tmp1=$func_stripname_result + case $build in + *mingw* ) # Actually, msys. + # Awkward: cmd appends spaces to result. + func_to_host_pathlist_result=` + ( cmd //c echo "$func_to_host_pathlist_tmp1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` + ;; + *cygwin* ) + func_to_host_pathlist_result=`cygpath -w -p "$func_to_host_pathlist_tmp1" | + $SED -e "$lt_sed_naive_backslashify"` + ;; + * ) + # unfortunately, winepath doesn't convert pathlists + func_to_host_pathlist_result="" + func_to_host_pathlist_oldIFS=$IFS + IFS=: + for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do + IFS=$func_to_host_pathlist_oldIFS + if test -n "$func_to_host_pathlist_f" ; then + func_to_host_path "$func_to_host_pathlist_f" + if test -n "$func_to_host_path_result" ; then + if test -z "$func_to_host_pathlist_result" ; then + func_to_host_pathlist_result="$func_to_host_path_result" + else + func_append func_to_host_pathlist_result ";$func_to_host_path_result" + fi + fi + fi + done + IFS=$func_to_host_pathlist_oldIFS + ;; + esac + if test -z "$func_to_host_pathlist_result"; then + func_error "Could not determine the host path(s) corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This may break if $1 contains DOS-style drive + # specifications. The fix is not to complicate the expression + # below, but for the user to provide a working wine installation + # with winepath so that path translation in the cross-to-mingw + # case works properly. + lt_replace_pathsep_nix_to_dos="s|:|;|g" + func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ + $SED -e "$lt_replace_pathsep_nix_to_dos"` + fi + # Now, add the leading and trailing path separators back + case "$1" in + :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" + ;; + esac + case "$1" in + *: ) func_append func_to_host_pathlist_result ";" + ;; + esac + ;; + esac + fi +} +# end: func_to_host_pathlist + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* declarations of non-ANSI functions */ +#if defined(__MINGW32__) +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined(__CYGWIN__) +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined (other platforms) ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined(_MSC_VER) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +# ifndef _INTPTR_T_DEFINED +# define _INTPTR_T_DEFINED +# define intptr_t int +# endif +#elif defined(__MINGW32__) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined(__CYGWIN__) +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined (other platforms) ... */ +#endif + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#undef LTWRAPPER_DEBUGPRINTF +#if defined LT_DEBUGWRAPPER +# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args +static void +ltwrapper_debugprintf (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); +} +#else +# define LTWRAPPER_DEBUGPRINTF(args) +#endif + +const char *program_name = NULL; + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_fatal (const char *message, ...); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <"))); + for (i = 0; i < newargc; i++) + { + LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : ""))); + } + +EOF + + case $host_os in + mingw*) + cat <<"EOF" + /* execv doesn't actually work on mingw as expected on unix */ + newargz = prepare_spawn (newargz); + rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); + if (rval == -1) + { + /* failed to start process */ + LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); + return 127; + } + return rval; +EOF + ;; + *) + cat <<"EOF" + execv (lt_argv_zero, newargz); + return rval; /* =127, but avoids unused variable warning */ +EOF + ;; + esac + + cat <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void *p = (void *) malloc (num); + if (!p) + lt_fatal ("Memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), + string) : NULL; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char) name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable (const char *path) +{ + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", + path ? (*path ? path : "EMPTY!") : "NULL!")); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", + wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal ("getcwd failed"); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", + tmp_pathspec)); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + char *errstr = strerror (errno); + lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal ("Could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +static void +lt_error_core (int exit_status, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s: %s: ", program_name, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + va_end (ap); +} + +void +lt_setenv (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", + (name ? name : ""), + (value ? value : ""))); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + (name ? name : ""), + (value ? value : ""))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + (name ? name : ""), + (value ? value : ""))); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -e 's/\([\\"]\)/\\\1/g' \ + -e 's/^/ fputs ("/' -e 's/$/\\n", f);/' + + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $opt_debug + case `eval "$file_magic_cmd \"\$1\" 2>/dev/null" | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir="$arg" + prev= + continue + ;; + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) deplibs="$deplibs $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# moreargs="$moreargs $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + weak_libs="$weak_libs $arg" + prev= + continue + ;; + xcclinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + compiler_flags="$compiler_flags $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + linker_flags="$linker_flags $qarg" + compiler_flags="$compiler_flags $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname '-L' '' "$arg" + dir=$func_stripname_result + if test -z "$dir"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "*) ;; + *) + deplibs="$deplibs -L$dir" + lib_search_path="$lib_search_path $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) dllsearchpath="$dllsearchpath:$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + deplibs="$deplibs System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + *-*-linux*) + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + deplibs="$deplibs $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + compiler_flags="$compiler_flags $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $func_quote_for_eval_result" + compiler_flags="$compiler_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + arg="$arg $wl$func_quote_for_eval_result" + compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" + linker_flags="$linker_flags $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # -64, -mips[0-9] enable 64-bit mode on the SGI compiler + # -r[0-9][0-9]* specifies the processor on the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler + # +DA*, +DD* enable 64-bit mode on the HP compiler + # -q* pass through compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* pass through architecture-specific + # compiler args for GCC + # -F/path gives path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + compiler_flags="$compiler_flags $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + dlfiles="$dlfiles $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + deplibs="$deplibs $arg" + old_deplibs="$old_deplibs $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + dlfiles="$dlfiles $arg" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + dlprefiles="$dlprefiles $arg" + prev= + else + deplibs="$deplibs $arg" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval "arg=\"$export_dynamic_flag_spec\"" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval "sys_lib_search_path=\"$sys_lib_search_path_spec\"" + eval "sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_duplicate_deps ; then + case "$libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + libs="$libs $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + esac + pre_post_deps="$pre_post_deps $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + case $lib in + *.la) func_source "$lib" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) deplibs="$deplibs $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + compiler_flags="$compiler_flags $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + dir=$func_stripname_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) lib="$deplib" ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + else + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + newdlprefiles="$newdlprefiles $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + newdlfiles="$newdlfiles $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && dlfiles="$dlfiles $dlopen" + test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $ladir/$objdir/$old_library" + old_convenience="$old_convenience $ladir/$objdir/$old_library" + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + dlprefiles="$dlprefiles $lib $dependency_libs" + else + newdlfiles="$newdlfiles $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$libdir" + absdir="$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + notinst_path="$notinst_path $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + newdlprefiles="$newdlprefiles $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + newdlprefiles="$newdlprefiles $dir/$dlname" + else + newdlprefiles="$newdlprefiles $dir/$linklib" + fi + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + newlib_search_path="$newlib_search_path $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + newlib_search_path="$newlib_search_path $func_stripname_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) temp_rpath="$temp_rpath$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + notinst_deplibs="$notinst_deplibs $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + echo + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + eval "libname=\"$libname_spec\"" + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval "soname=\"$soname_spec\"" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$absdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + add_dir="$add_dir -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system can not link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + *) temp_deplibs="$temp_deplibs $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + newlib_search_path="$newlib_search_path $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + if $opt_duplicate_deps ; then + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi + tmp_libs="$tmp_libs $deplib" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_dirname "$deplib" "" "." + dir="$func_dirname_result" + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\$$var + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + ;; + *) tmp_libs="$tmp_libs $deplib" ;; + esac + done + eval $var=\$tmp_libs + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + tmp_libs="$tmp_libs $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + objs="$objs$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval "shared_ext=\"$shrext_cmds\"" + eval "libname=\"$libname_spec\"" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval "shared_ext=\"$shrext_cmds\"" + eval "libname=\"$libname_spec\"" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + libobjs="$libobjs $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|qnx|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + libobjs="$libobjs $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + removelist="$removelist $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) dlfiles="$dlfiles $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) dlprefiles="$dlprefiles $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + deplibs="$deplibs System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + deplibs="$deplibs -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval "$file_magic_cmd \"\$potlib\"" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + eval "libname=\"$libname_spec\"" + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval "flag=\"$hardcode_libdir_flag_spec\"" + dep_rpath="$dep_rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + if test -n "$hardcode_libdir_flag_spec_ld"; then + eval "dep_rpath=\"$hardcode_libdir_flag_spec_ld\"" + else + eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + eval $runpath_var=\$rpath\$$runpath_var + export $runpath_var + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval $shlibpath_var=\$shlibpath\$$shlibpath_var + export $shlibpath_var + fi + + # Get the real and link names of the library. + eval "shared_ext=\"$shrext_cmds\"" + eval "library_names=\"$library_names_spec\"" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval "soname=\"$soname_spec\"" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + linknames="$linknames $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + delfiles="$delfiles $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval "cmd=\"$cmd\"" + func_len " $cmd" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || $ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols" + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval "libobjs=\"\$libobjs $whole_archive_flag_spec\"" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval "flag=\"$thread_safe_flag_spec\"" + linker_flags="$linker_flags $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$mode" = relink; then + $opt_dry_run || (cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U) || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval "test_cmds=\"$module_expsym_cmds\"" + cmds=$module_expsym_cmds + else + eval "test_cmds=\"$module_cmds\"" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval "test_cmds=\"$archive_expsym_cmds\"" + cmds=$archive_expsym_cmds + else + eval "test_cmds=\"$archive_cmds\"" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + $ECHO "$obj" >> $output + done + echo ')' >> $output + delfiles="$delfiles $output" + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + $ECHO "$obj" >> $output + done + delfiles="$delfiles $output" + output=$firstobj\"$file_list_spec$output\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval "test_cmds=\"$reload_cmds\"" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval "concat_cmds=\"$reload_cmds\"" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval "concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval "concat_cmds=\"\${concat_cmds}$reload_cmds\"" + if test -n "$last_robj"; then + eval "concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"" + fi + delfiles="$delfiles $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval "concat_cmds=\"\$concat_cmds$export_symbols_cmds\"" + if test -n "$last_robj"; then + eval "concat_cmds=\"\$concat_cmds~\$RM $last_robj\"" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || $ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols" + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval "libobjs=\"\$libobjs $whole_archive_flag_spec\"" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval "cmds=\"\$cmds~\$RM $delfiles\"" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + libobjs="$libobjs $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval "cmd=\"$cmd\"" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$mode" = relink; then + $opt_dry_run || (cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname) || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval "tmp_whole_archive_flags=\"$whole_archive_flag_spec\"" + reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + generated="$generated $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || echo timestamp > $libobj || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + new_libs="$new_libs -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$new_libs $deplib" ;; + esac + ;; + *) new_libs="$new_libs $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + compile_command="$compile_command $compile_deplibs" + finalize_command="$finalize_command $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval "flag=\"$hardcode_libdir_flag_spec\"" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) dllsearchpath="$dllsearchpath:$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) dllsearchpath="$dllsearchpath:$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval "rpath=\" $hardcode_libdir_flag_spec\"" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval "flag=\"$hardcode_libdir_flag_spec\"" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval "rpath=\" $hardcode_libdir_flag_spec\"" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=no + ;; + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + oldobjs="$oldobjs $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $addlibs + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + + func_extract_archives $gentop $dlprefiles + oldobjs="$oldobjs $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + oldobjs="$oldobjs $gentop/$newobj" + ;; + *) oldobjs="$oldobjs $obj" ;; + esac + done + fi + eval "cmds=\"$old_archive_cmds\"" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval "test_cmds=\"$old_archive_cmds\"" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval "concat_cmds=\"\${concat_cmds}$old_archive_cmds\"" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval "cmds=\"\$concat_cmds\"" + else + eval "cmds=\"\$concat_cmds~\$old_archive_cmds\"" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + newdependency_libs="$newdependency_libs $libdir/$name" + ;; + *) newdependency_libs="$newdependency_libs $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlfiles="$newdlfiles $libdir/$name" + ;; + *) newdlfiles="$newdlfiles $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + newdlprefiles="$newdlprefiles $libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlfiles="$newdlfiles $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + newdlprefiles="$newdlprefiles $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test "x$bindir" != x ; + then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$mode" = link || test "$mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) RM="$RM $arg"; rmforce=yes ;; + -*) RM="$RM $arg" ;; + *) files="$files $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + origobjdir="$objdir" + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + objdir="$origobjdir" + else + objdir="$dir/$origobjdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$mode" = uninstall && objdir="$dir" + + # Remember objdir for removal later, being careful to avoid duplicates + if test "$mode" = clean; then + case " $rmdirs " in + *" $objdir "*) ;; + *) rmdirs="$rmdirs $objdir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $objdir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + + case "$mode" in + clean) + case " $library_names " in + # " " in the beginning catches empty $dlname + *" $dlname "*) ;; + *) rmfiles="$rmfiles $objdir/$dlname" ;; + esac + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + rmfiles="$rmfiles $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + rmfiles="$rmfiles $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + rmfiles="$rmfiles $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + rmfiles="$rmfiles $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + rmfiles="$rmfiles $objdir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + rmfiles="$rmfiles $objdir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + objdir="$origobjdir" + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$mode" = uninstall || test "$mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/backtrace-sys-0.1.16/src/libbacktrace/missing b/backtrace-sys-0.1.16/src/libbacktrace/missing new file mode 100755 index 000000000..f62bbae30 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/missing @@ -0,0 +1,215 @@ +#! /bin/sh +# Common wrapper for a few potentially missing GNU programs. + +scriptversion=2013-10-28.13; # UTC + +# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# Originally written by Fran,cois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try '$0 --help' for more information" + exit 1 +fi + +case $1 in + + --is-lightweight) + # Used by our autoconf macros to check whether the available missing + # script is modern enough. + exit 0 + ;; + + --run) + # Back-compat with the calling convention used by older automake. + shift + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due +to PROGRAM being missing or too old. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal autoconf autoheader autom4te automake makeinfo + bison yacc flex lex help2man + +Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and +'g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: unknown '$1' option" + echo 1>&2 "Try '$0 --help' for more information" + exit 1 + ;; + +esac + +# Run the given program, remember its exit status. +"$@"; st=$? + +# If it succeeded, we are done. +test $st -eq 0 && exit 0 + +# Also exit now if we it failed (or wasn't found), and '--version' was +# passed; such an option is passed most likely to detect whether the +# program is present and works. +case $2 in --version|--help) exit $st;; esac + +# Exit code 63 means version mismatch. This often happens when the user +# tries to use an ancient version of a tool on a file that requires a +# minimum version. +if test $st -eq 63; then + msg="probably too old" +elif test $st -eq 127; then + # Program was missing. + msg="missing on your system" +else + # Program was found and executed, but failed. Give up. + exit $st +fi + +perl_URL=http://www.perl.org/ +flex_URL=http://flex.sourceforge.net/ +gnu_software_URL=http://www.gnu.org/software + +program_details () +{ + case $1 in + aclocal|automake) + echo "The '$1' program is part of the GNU Automake package:" + echo "<$gnu_software_URL/automake>" + echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/autoconf>" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + autoconf|autom4te|autoheader) + echo "The '$1' program is part of the GNU Autoconf package:" + echo "<$gnu_software_URL/autoconf/>" + echo "It also requires GNU m4 and Perl in order to run:" + echo "<$gnu_software_URL/m4/>" + echo "<$perl_URL>" + ;; + esac +} + +give_advice () +{ + # Normalize program name to check for. + normalized_program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + + printf '%s\n' "'$1' is $msg." + + configure_deps="'configure.ac' or m4 files included by 'configure.ac'" + case $normalized_program in + autoconf*) + echo "You should only need it if you modified 'configure.ac'," + echo "or m4 files included by it." + program_details 'autoconf' + ;; + autoheader*) + echo "You should only need it if you modified 'acconfig.h' or" + echo "$configure_deps." + program_details 'autoheader' + ;; + automake*) + echo "You should only need it if you modified 'Makefile.am' or" + echo "$configure_deps." + program_details 'automake' + ;; + aclocal*) + echo "You should only need it if you modified 'acinclude.m4' or" + echo "$configure_deps." + program_details 'aclocal' + ;; + autom4te*) + echo "You might have modified some maintainer files that require" + echo "the 'autom4te' program to be rebuilt." + program_details 'autom4te' + ;; + bison*|yacc*) + echo "You should only need it if you modified a '.y' file." + echo "You may want to install the GNU Bison package:" + echo "<$gnu_software_URL/bison/>" + ;; + lex*|flex*) + echo "You should only need it if you modified a '.l' file." + echo "You may want to install the Fast Lexical Analyzer package:" + echo "<$flex_URL>" + ;; + help2man*) + echo "You should only need it if you modified a dependency" \ + "of a man page." + echo "You may want to install the GNU Help2man package:" + echo "<$gnu_software_URL/help2man/>" + ;; + makeinfo*) + echo "You should only need it if you modified a '.texi' file, or" + echo "any other file indirectly affecting the aspect of the manual." + echo "You might want to install the Texinfo package:" + echo "<$gnu_software_URL/texinfo/>" + echo "The spurious makeinfo call might also be the consequence of" + echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" + echo "want to install GNU make:" + echo "<$gnu_software_URL/make/>" + ;; + *) + echo "You might have modified some files without having the proper" + echo "tools for further handling them. Check the 'README' file, it" + echo "often tells you about the needed prerequisites for installing" + echo "this package. You may also peek at any GNU archive site, in" + echo "case some other package contains this missing '$1' program." + ;; + esac +} + +give_advice "$1" | sed -e '1s/^/WARNING: /' \ + -e '2,$s/^/ /' >&2 + +# Propagate the correct exit status (expected to be 127 for a program +# not found, 63 for a program that failed due to version mismatch). +exit $st + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/backtrace-sys-0.1.16/src/libbacktrace/mmap.c b/backtrace-sys-0.1.16/src/libbacktrace/mmap.c new file mode 100644 index 000000000..e30d1c1a3 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/mmap.c @@ -0,0 +1,303 @@ +/* mmap.c -- Memory allocation with mmap. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +/* Memory allocation on systems that provide anonymous mmap. This + permits the backtrace functions to be invoked from a signal + handler, assuming that mmap is async-signal safe. */ + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +/* A list of free memory blocks. */ + +struct backtrace_freelist_struct +{ + /* Next on list. */ + struct backtrace_freelist_struct *next; + /* Size of this block, including this structure. */ + size_t size; +}; + +/* Free memory allocated by backtrace_alloc. */ + +static void +backtrace_free_locked (struct backtrace_state *state, void *addr, size_t size) +{ + /* Just leak small blocks. We don't have to be perfect. */ + if (size >= sizeof (struct backtrace_freelist_struct)) + { + struct backtrace_freelist_struct *p; + + p = (struct backtrace_freelist_struct *) addr; + p->next = state->freelist; + p->size = size; + state->freelist = p; + } +} + +/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't + report an error. */ + +void * +backtrace_alloc (struct backtrace_state *state, + size_t size, backtrace_error_callback error_callback, + void *data) +{ + void *ret; + int locked; + struct backtrace_freelist_struct **pp; + size_t pagesize; + size_t asksize; + void *page; + + ret = NULL; + + /* If we can acquire the lock, then see if there is space on the + free list. If we can't acquire the lock, drop straight into + using mmap. __sync_lock_test_and_set returns the old state of + the lock, so we have acquired it if it returns 0. */ + + if (!state->threaded) + locked = 1; + else + locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0; + + if (locked) + { + for (pp = &state->freelist; *pp != NULL; pp = &(*pp)->next) + { + if ((*pp)->size >= size) + { + struct backtrace_freelist_struct *p; + + p = *pp; + *pp = p->next; + + /* Round for alignment; we assume that no type we care about + is more than 8 bytes. */ + size = (size + 7) & ~ (size_t) 7; + if (size < p->size) + backtrace_free_locked (state, (char *) p + size, + p->size - size); + + ret = (void *) p; + + break; + } + } + + if (state->threaded) + __sync_lock_release (&state->lock_alloc); + } + + if (ret == NULL) + { + /* Allocate a new page. */ + + pagesize = getpagesize (); + asksize = (size + pagesize - 1) & ~ (pagesize - 1); + page = mmap (NULL, asksize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (page == MAP_FAILED) + { + if (error_callback) + error_callback (data, "mmap", errno); + } + else + { + size = (size + 7) & ~ (size_t) 7; + if (size < asksize) + backtrace_free (state, (char *) page + size, asksize - size, + error_callback, data); + + ret = page; + } + } + + return ret; +} + +/* Free memory allocated by backtrace_alloc. */ + +void +backtrace_free (struct backtrace_state *state, void *addr, size_t size, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + int locked; + + /* If we are freeing a large aligned block, just release it back to + the system. This case arises when growing a vector for a large + binary with lots of debug info. Calling munmap here may cause us + to call mmap again if there is also a large shared library; we + just live with that. */ + if (size >= 16 * 4096) + { + size_t pagesize; + + pagesize = getpagesize (); + if (((uintptr_t) addr & (pagesize - 1)) == 0 + && (size & (pagesize - 1)) == 0) + { + /* If munmap fails for some reason, just add the block to + the freelist. */ + if (munmap (addr, size) == 0) + return; + } + } + + /* If we can acquire the lock, add the new space to the free list. + If we can't acquire the lock, just leak the memory. + __sync_lock_test_and_set returns the old state of the lock, so we + have acquired it if it returns 0. */ + + if (!state->threaded) + locked = 1; + else + locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0; + + if (locked) + { + backtrace_free_locked (state, addr, size); + + if (state->threaded) + __sync_lock_release (&state->lock_alloc); + } +} + +/* Grow VEC by SIZE bytes. */ + +void * +backtrace_vector_grow (struct backtrace_state *state,size_t size, + backtrace_error_callback error_callback, + void *data, struct backtrace_vector *vec) +{ + void *ret; + + if (size > vec->alc) + { + size_t pagesize; + size_t alc; + void *base; + + pagesize = getpagesize (); + alc = vec->size + size; + if (vec->size == 0) + alc = 16 * size; + else if (alc < pagesize) + { + alc *= 2; + if (alc > pagesize) + alc = pagesize; + } + else + { + alc *= 2; + alc = (alc + pagesize - 1) & ~ (pagesize - 1); + } + base = backtrace_alloc (state, alc, error_callback, data); + if (base == NULL) + return NULL; + if (vec->base != NULL) + { + memcpy (base, vec->base, vec->size); + backtrace_free (state, vec->base, vec->size + vec->alc, + error_callback, data); + } + vec->base = base; + vec->alc = alc - vec->size; + } + + ret = (char *) vec->base + vec->size; + vec->size += size; + vec->alc -= size; + return ret; +} + +/* Finish the current allocation on VEC. */ + +void * +backtrace_vector_finish ( + struct backtrace_state *state ATTRIBUTE_UNUSED, + struct backtrace_vector *vec, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + void *ret; + + ret = vec->base; + vec->base = (char *) vec->base + vec->size; + vec->size = 0; + return ret; +} + +/* Release any extra space allocated for VEC. */ + +int +backtrace_vector_release (struct backtrace_state *state, + struct backtrace_vector *vec, + backtrace_error_callback error_callback, + void *data) +{ + size_t size; + size_t alc; + size_t aligned; + + /* Make sure that the block that we free is aligned on an 8-byte + boundary. */ + size = vec->size; + alc = vec->alc; + aligned = (size + 7) & ~ (size_t) 7; + alc -= aligned - size; + + backtrace_free (state, (char *) vec->base + aligned, alc, + error_callback, data); + vec->alc = 0; + return 1; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/mmapio.c b/backtrace-sys-0.1.16/src/libbacktrace/mmapio.c new file mode 100644 index 000000000..8a9ba8e7b --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/mmapio.c @@ -0,0 +1,100 @@ +/* mmapio.c -- File views using mmap. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +/* This file implements file views and memory allocation when mmap is + available. */ + +/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */ + +int +backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED, + int descriptor, off_t offset, size_t size, + backtrace_error_callback error_callback, + void *data, struct backtrace_view *view) +{ + size_t pagesize; + unsigned int inpage; + off_t pageoff; + void *map; + + pagesize = getpagesize (); + inpage = offset % pagesize; + pageoff = offset - inpage; + + size += inpage; + size = (size + (pagesize - 1)) & ~ (pagesize - 1); + + map = mmap (NULL, size, PROT_READ, MAP_PRIVATE, descriptor, pageoff); + if (map == MAP_FAILED) + { + error_callback (data, "mmap", errno); + return 0; + } + + view->data = (char *) map + inpage; + view->base = map; + view->len = size; + + return 1; +} + +/* Release a view read by backtrace_get_view. */ + +void +backtrace_release_view (struct backtrace_state *state ATTRIBUTE_UNUSED, + struct backtrace_view *view, + backtrace_error_callback error_callback, + void *data) +{ + union { + const void *cv; + void *v; + } const_cast; + + const_cast.cv = view->base; + if (munmap (const_cast.v, view->len) < 0) + error_callback (data, "munmap", errno); +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/nounwind.c b/backtrace-sys-0.1.16/src/libbacktrace/nounwind.c new file mode 100644 index 000000000..0deaeef0a --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/nounwind.c @@ -0,0 +1,66 @@ +/* backtrace.c -- Entry point for stack backtrace library. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include + +#include "backtrace.h" + +#include "internal.h" + +/* This source file is compiled if the unwind library is not + available. */ + +int +backtrace_full (struct backtrace_state *state ATTRIBUTE_UNUSED, + int skip ATTRIBUTE_UNUSED, + backtrace_full_callback callback ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, void *data) +{ + error_callback (data, + "no stack trace because unwind library not available", + 0); + return 0; +} + +int +backtrace_simple (struct backtrace_state *state ATTRIBUTE_UNUSED, + int skip ATTRIBUTE_UNUSED, + backtrace_simple_callback callback ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, void *data) +{ + error_callback (data, + "no stack trace because unwind library not available", + 0); + return 0; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/pecoff.c b/backtrace-sys-0.1.16/src/libbacktrace/pecoff.c new file mode 100644 index 000000000..c7d32aa6b --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/pecoff.c @@ -0,0 +1,937 @@ +/* pecoff.c -- Get debug data from a PE/COFFF file for backtraces. + Copyright (C) 2015-2016 Free Software Foundation, Inc. + Adapted from elf.c by Tristan Gingold, AdaCore. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +/* Coff file header. */ + +typedef struct { + uint16_t machine; + uint16_t number_of_sections; + uint32_t time_date_stamp; + uint32_t pointer_to_symbol_table; + uint32_t number_of_symbols; + uint16_t size_of_optional_header; + uint16_t characteristics; +} b_coff_file_header; + +/* Coff optional header. */ + +typedef struct { + uint16_t magic; + uint8_t major_linker_version; + uint8_t minor_linker_version; + uint32_t size_of_code; + uint32_t size_of_initialized_data; + uint32_t size_of_uninitialized_data; + uint32_t address_of_entry_point; + uint32_t base_of_code; + union { + struct { + uint32_t base_of_data; + uint32_t image_base; + } pe; + struct { + uint64_t image_base; + } pep; + } u; +} b_coff_optional_header; + +/* Values of magic in optional header. */ + +#define PE_MAGIC 0x10b /* PE32 executable. */ +#define PEP_MAGIC 0x20b /* PE32+ executable (for 64bit targets). */ + +/* Coff section header. */ + +typedef struct { + char name[8]; + uint32_t virtual_size; + uint32_t virtual_address; + uint32_t size_of_raw_data; + uint32_t pointer_to_raw_data; + uint32_t pointer_to_relocations; + uint32_t pointer_to_line_numbers; + uint16_t number_of_relocations; + uint16_t number_of_line_numbers; + uint32_t characteristics; +} b_coff_section_header; + +/* Coff symbol name. */ + +typedef union { + char short_name[8]; + struct { + unsigned char zeroes[4]; + unsigned char off[4]; + } long_name; +} b_coff_name; + +/* Coff symbol (external representation which is unaligned). */ + +typedef struct { + b_coff_name name; + unsigned char value[4]; + unsigned char section_number[2]; + unsigned char type[2]; + unsigned char storage_class; + unsigned char number_of_aux_symbols; +} b_coff_external_symbol; + +/* Symbol types. */ + +#define N_TBSHFT 4 /* Shift for the derived type. */ +#define IMAGE_SYM_DTYPE_FUNCTION 2 /* Function derived type. */ + +/* Size of a coff symbol. */ + +#define SYM_SZ 18 + +/* Coff symbol, internal representation (aligned). */ + +typedef struct { + const char *name; + uint32_t value; + int16_t sec; + uint16_t type; + uint16_t sc; +} b_coff_internal_symbol; + +/* An index of sections we care about. */ + +enum debug_section +{ + DEBUG_INFO, + DEBUG_LINE, + DEBUG_ABBREV, + DEBUG_RANGES, + DEBUG_STR, + DEBUG_MAX +}; + +/* Names of sections, indexed by enum debug_section. */ + +static const char * const debug_section_names[DEBUG_MAX] = +{ + ".debug_info", + ".debug_line", + ".debug_abbrev", + ".debug_ranges", + ".debug_str" +}; + +/* Information we gather for the sections we care about. */ + +struct debug_section_info +{ + /* Section file offset. */ + off_t offset; + /* Section size. */ + size_t size; + /* Section contents, after read from file. */ + const unsigned char *data; +}; + +/* Information we keep for an coff symbol. */ + +struct coff_symbol +{ + /* The name of the symbol. */ + const char *name; + /* The address of the symbol. */ + uintptr_t address; +}; + +/* Information to pass to coff_syminfo. */ + +struct coff_syminfo_data +{ + /* Symbols for the next module. */ + struct coff_syminfo_data *next; + /* The COFF symbols, sorted by address. */ + struct coff_symbol *symbols; + /* The number of symbols. */ + size_t count; +}; + +/* A dummy callback function used when we can't find any debug info. */ + +static int +coff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, + uintptr_t pc ATTRIBUTE_UNUSED, + backtrace_full_callback callback ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, void *data) +{ + error_callback (data, "no debug info in PE/COFF executable", -1); + return 0; +} + +/* A dummy callback function used when we can't find a symbol + table. */ + +static void +coff_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, + uintptr_t addr ATTRIBUTE_UNUSED, + backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback, void *data) +{ + error_callback (data, "no symbol table in PE/COFF executable", -1); +} + +/* Read a potentially unaligned 4 byte word at P, using native endianness. */ + +static uint32_t +coff_read4 (const unsigned char *p) +{ + uint32_t res; + + memcpy (&res, p, 4); + return res; +} + +/* Read a potentially unaligned 2 byte word at P, using native endianness. + All 2 byte word in symbols are always aligned, but for coherency all + fields are declared as char arrays. */ + +static uint16_t +coff_read2 (const unsigned char *p) +{ + uint16_t res; + + memcpy (&res, p, sizeof (res)); + return res; +} + +/* Return the length (without the trailing 0) of a COFF short name. */ + +static size_t +coff_short_name_len (const char *name) +{ + int i; + + for (i = 0; i < 8; i++) + if (name[i] == 0) + return i; + return 8; +} + +/* Return true iff COFF short name CNAME is the same as NAME (a NUL-terminated + string). */ + +static int +coff_short_name_eq (const char *name, const char *cname) +{ + int i; + + for (i = 0; i < 8; i++) + { + if (name[i] != cname[i]) + return 0; + if (name[i] == 0) + return 1; + } + return name[8] == 0; +} + +/* Return true iff NAME is the same as string at offset OFF. */ + +static int +coff_long_name_eq (const char *name, unsigned int off, + struct backtrace_view *str_view) +{ + if (off >= str_view->len) + return 0; + return strcmp (name, (const char *)str_view->data + off) == 0; +} + +/* Compare struct coff_symbol for qsort. */ + +static int +coff_symbol_compare (const void *v1, const void *v2) +{ + const struct coff_symbol *e1 = (const struct coff_symbol *) v1; + const struct coff_symbol *e2 = (const struct coff_symbol *) v2; + + if (e1->address < e2->address) + return -1; + else if (e1->address > e2->address) + return 1; + else + return 0; +} + +/* Convert SYM to internal (and aligned) format ISYM, using string table + from STRTAB and STRTAB_SIZE, and number of sections SECTS_NUM. + Return -1 in case of error (invalid section number or string index). */ + +static int +coff_expand_symbol (b_coff_internal_symbol *isym, + const b_coff_external_symbol *sym, + uint16_t sects_num, + const unsigned char *strtab, size_t strtab_size) +{ + isym->type = coff_read2 (sym->type); + isym->sec = coff_read2 (sym->section_number); + isym->sc = sym->storage_class; + + if (isym->sec > 0 && (uint16_t) isym->sec > sects_num) + return -1; + if (sym->name.short_name[0] != 0) + isym->name = sym->name.short_name; + else + { + uint32_t off = coff_read4 (sym->name.long_name.off); + + if (off >= strtab_size) + return -1; + isym->name = (const char *) strtab + off; + } + return 0; +} + +/* Return true iff SYM is a defined symbol for a function. Data symbols + aren't considered because they aren't easily identified (same type as + section names, presence of symbols defined by the linker script). */ + +static int +coff_is_function_symbol (const b_coff_internal_symbol *isym) +{ + return (isym->type >> N_TBSHFT) == IMAGE_SYM_DTYPE_FUNCTION + && isym->sec > 0; +} + +/* Initialize the symbol table info for coff_syminfo. */ + +static int +coff_initialize_syminfo (struct backtrace_state *state, + uintptr_t base_address, + const b_coff_section_header *sects, size_t sects_num, + const b_coff_external_symbol *syms, size_t syms_size, + const unsigned char *strtab, size_t strtab_size, + backtrace_error_callback error_callback, + void *data, struct coff_syminfo_data *sdata) +{ + size_t syms_count; + char *coff_symstr; + size_t coff_symstr_len; + size_t coff_symbol_count; + size_t coff_symbol_size; + struct coff_symbol *coff_symbols; + struct coff_symbol *coff_sym; + char *coff_str; + size_t i; + + syms_count = syms_size / SYM_SZ; + + /* We only care about function symbols. Count them. Also count size of + strings for in-symbol names. */ + coff_symbol_count = 0; + coff_symstr_len = 0; + for (i = 0; i < syms_count; ++i) + { + const b_coff_external_symbol *asym = &syms[i]; + b_coff_internal_symbol isym; + + if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size) < 0) + { + error_callback (data, "invalid section or offset in coff symbol", 0); + return 0; + } + if (coff_is_function_symbol (&isym)) + { + ++coff_symbol_count; + if (asym->name.short_name[0] != 0) + coff_symstr_len += coff_short_name_len (asym->name.short_name) + 1; + } + + i += asym->number_of_aux_symbols; + } + + coff_symbol_size = (coff_symbol_count + 1) * sizeof (struct coff_symbol); + coff_symbols = ((struct coff_symbol *) + backtrace_alloc (state, coff_symbol_size, error_callback, + data)); + if (coff_symbols == NULL) + return 0; + + /* Allocate memory for symbols strings. */ + if (coff_symstr_len > 0) + { + coff_symstr = ((char *) + backtrace_alloc (state, coff_symstr_len, error_callback, + data)); + if (coff_symstr == NULL) + { + backtrace_free (state, coff_symbols, coff_symbol_size, + error_callback, data); + return 0; + } + } + else + coff_symstr = NULL; + + /* Copy symbols. */ + coff_sym = coff_symbols; + coff_str = coff_symstr; + for (i = 0; i < syms_count; ++i) + { + const b_coff_external_symbol *asym = &syms[i]; + b_coff_internal_symbol isym; + + if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size)) + { + /* Should not fail, as it was already tested in the previous + loop. */ + abort (); + } + if (coff_is_function_symbol (&isym)) + { + const char *name; + int16_t secnum; + + if (asym->name.short_name[0] != 0) + { + size_t len = coff_short_name_len (isym.name); + name = coff_str; + memcpy (coff_str, isym.name, len); + coff_str[len] = 0; + coff_str += len + 1; + } + else + name = isym.name; + + /* Strip leading '_'. */ + if (name[0] == '_') + name++; + + /* Symbol value is section relative, so we need to read the address + of its section. */ + secnum = coff_read2 (asym->section_number); + + coff_sym->name = name; + coff_sym->address = (coff_read4 (asym->value) + + sects[secnum - 1].virtual_address + + base_address); + coff_sym++; + } + + i += asym->number_of_aux_symbols; + } + + /* End of symbols marker. */ + coff_sym->name = NULL; + coff_sym->address = -1; + + backtrace_qsort (coff_symbols, coff_symbol_count, + sizeof (struct coff_symbol), coff_symbol_compare); + + sdata->next = NULL; + sdata->symbols = coff_symbols; + sdata->count = coff_symbol_count; + + return 1; +} + +/* Add EDATA to the list in STATE. */ + +static void +coff_add_syminfo_data (struct backtrace_state *state, + struct coff_syminfo_data *sdata) +{ + if (!state->threaded) + { + struct coff_syminfo_data **pp; + + for (pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data; + *pp != NULL; + pp = &(*pp)->next) + ; + *pp = sdata; + } + else + { + while (1) + { + struct coff_syminfo_data **pp; + + pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data; + + while (1) + { + struct coff_syminfo_data *p; + + p = backtrace_atomic_load_pointer (pp); + + if (p == NULL) + break; + + pp = &p->next; + } + + if (__sync_bool_compare_and_swap (pp, NULL, sdata)) + break; + } + } +} + +/* Compare an ADDR against an elf_symbol for bsearch. We allocate one + extra entry in the array so that this can look safely at the next + entry. */ + +static int +coff_symbol_search (const void *vkey, const void *ventry) +{ + const uintptr_t *key = (const uintptr_t *) vkey; + const struct coff_symbol *entry = (const struct coff_symbol *) ventry; + uintptr_t addr; + + addr = *key; + if (addr < entry->address) + return -1; + else if (addr >= entry[1].address) + return 1; + else + return 0; +} + +/* Return the symbol name and value for an ADDR. */ + +static void +coff_syminfo (struct backtrace_state *state, uintptr_t addr, + backtrace_syminfo_callback callback, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data) +{ + struct coff_syminfo_data *sdata; + struct coff_symbol *sym = NULL; + + if (!state->threaded) + { + for (sdata = (struct coff_syminfo_data *) state->syminfo_data; + sdata != NULL; + sdata = sdata->next) + { + sym = ((struct coff_symbol *) + bsearch (&addr, sdata->symbols, sdata->count, + sizeof (struct coff_symbol), coff_symbol_search)); + if (sym != NULL) + break; + } + } + else + { + struct coff_syminfo_data **pp; + + pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data; + while (1) + { + sdata = backtrace_atomic_load_pointer (pp); + if (sdata == NULL) + break; + + sym = ((struct coff_symbol *) + bsearch (&addr, sdata->symbols, sdata->count, + sizeof (struct coff_symbol), coff_symbol_search)); + if (sym != NULL) + break; + + pp = &sdata->next; + } + } + + if (sym == NULL) + callback (data, addr, NULL, 0, 0); + else + callback (data, addr, sym->name, sym->address, 0); +} + +/* Add the backtrace data for one PE/COFF file. Returns 1 on success, + 0 on failure (in both cases descriptor is closed). */ + +static int +coff_add (struct backtrace_state *state, int descriptor, + backtrace_error_callback error_callback, void *data, + fileline *fileline_fn, int *found_sym, int *found_dwarf) +{ + struct backtrace_view fhdr_view; + off_t fhdr_off; + int magic_ok; + b_coff_file_header fhdr; + off_t opt_sects_off; + size_t opt_sects_size; + unsigned int sects_num; + struct backtrace_view sects_view; + int sects_view_valid; + const b_coff_optional_header *opt_hdr; + const b_coff_section_header *sects; + struct backtrace_view str_view; + int str_view_valid; + size_t str_size; + off_t str_off; + struct backtrace_view syms_view; + off_t syms_off; + size_t syms_size; + int syms_view_valid; + unsigned int syms_num; + unsigned int i; + struct debug_section_info sections[DEBUG_MAX]; + off_t min_offset; + off_t max_offset; + struct backtrace_view debug_view; + int debug_view_valid; + uintptr_t image_base; + + *found_sym = 0; + *found_dwarf = 0; + + sects_view_valid = 0; + syms_view_valid = 0; + str_view_valid = 0; + debug_view_valid = 0; + + /* Map the MS-DOS stub (if any) and extract file header offset. */ + if (!backtrace_get_view (state, descriptor, 0, 0x40, error_callback, + data, &fhdr_view)) + goto fail; + + { + const char *vptr = (const char *)fhdr_view.data; + + if (vptr[0] == 'M' && vptr[1] == 'Z') + memcpy (&fhdr_off, vptr + 0x3c, 4); + else + fhdr_off = 0; + } + + backtrace_release_view (state, &fhdr_view, error_callback, data); + + /* Map the coff file header. */ + if (!backtrace_get_view (state, descriptor, fhdr_off, + sizeof (b_coff_file_header) + 4, + error_callback, data, &fhdr_view)) + goto fail; + + if (fhdr_off != 0) + { + const char *magic = (const char *) fhdr_view.data; + magic_ok = memcmp (magic, "PE\0", 4) == 0; + fhdr_off += 4; + + memcpy (&fhdr, fhdr_view.data + 4, sizeof fhdr); + } + else + { + memcpy (&fhdr, fhdr_view.data, sizeof fhdr); + /* TODO: test fhdr.machine for coff but non-PE platforms. */ + magic_ok = 0; + } + backtrace_release_view (state, &fhdr_view, error_callback, data); + + if (!magic_ok) + { + error_callback (data, "executable file is not COFF", 0); + goto fail; + } + + sects_num = fhdr.number_of_sections; + syms_num = fhdr.number_of_symbols; + + opt_sects_off = fhdr_off + sizeof (fhdr); + opt_sects_size = (fhdr.size_of_optional_header + + sects_num * sizeof (b_coff_section_header)); + + /* To translate PC to file/line when using DWARF, we need to find + the .debug_info and .debug_line sections. */ + + /* Read the optional header and the section headers. */ + + if (!backtrace_get_view (state, descriptor, opt_sects_off, opt_sects_size, + error_callback, data, §s_view)) + goto fail; + sects_view_valid = 1; + opt_hdr = (const b_coff_optional_header *) sects_view.data; + sects = (const b_coff_section_header *) + (sects_view.data + fhdr.size_of_optional_header); + + if (fhdr.size_of_optional_header > sizeof (*opt_hdr)) + { + if (opt_hdr->magic == PE_MAGIC) + image_base = opt_hdr->u.pe.image_base; + else if (opt_hdr->magic == PEP_MAGIC) + image_base = opt_hdr->u.pep.image_base; + else + { + error_callback (data, "bad magic in PE optional header", 0); + goto fail; + } + } + else + image_base = 0; + + /* Read the symbol table and the string table. */ + + if (fhdr.pointer_to_symbol_table == 0) + { + /* No symbol table, no string table. */ + str_off = 0; + str_size = 0; + syms_num = 0; + syms_size = 0; + } + else + { + /* Symbol table is followed by the string table. The string table + starts with its length (on 4 bytes). + Map the symbol table and the length of the string table. */ + syms_off = fhdr.pointer_to_symbol_table; + syms_size = syms_num * SYM_SZ; + + if (!backtrace_get_view (state, descriptor, syms_off, syms_size + 4, + error_callback, data, &syms_view)) + goto fail; + syms_view_valid = 1; + + memcpy (&str_size, syms_view.data + syms_size, 4); + + str_off = syms_off + syms_size; + + if (str_size > 4) + { + /* Map string table (including the length word). */ + + if (!backtrace_get_view (state, descriptor, str_off, str_size, + error_callback, data, &str_view)) + goto fail; + str_view_valid = 1; + } + } + + memset (sections, 0, sizeof sections); + + /* Look for the symbol table. */ + for (i = 0; i < sects_num; ++i) + { + const b_coff_section_header *s = sects + i; + unsigned int str_off; + int j; + + if (s->name[0] == '/') + { + /* Extended section name. */ + str_off = atoi (s->name + 1); + } + else + str_off = 0; + + for (j = 0; j < (int) DEBUG_MAX; ++j) + { + const char *dbg_name = debug_section_names[j]; + int match; + + if (str_off != 0) + match = coff_long_name_eq (dbg_name, str_off, &str_view); + else + match = coff_short_name_eq (dbg_name, s->name); + if (match) + { + sections[j].offset = s->pointer_to_raw_data; + sections[j].size = s->virtual_size <= s->size_of_raw_data ? + s->virtual_size : s->size_of_raw_data; + break; + } + } + } + + if (syms_num != 0) + { + struct coff_syminfo_data *sdata; + + sdata = ((struct coff_syminfo_data *) + backtrace_alloc (state, sizeof *sdata, error_callback, data)); + if (sdata == NULL) + goto fail; + + if (!coff_initialize_syminfo (state, image_base, + sects, sects_num, + syms_view.data, syms_size, + str_view.data, str_size, + error_callback, data, sdata)) + { + backtrace_free (state, sdata, sizeof *sdata, error_callback, data); + goto fail; + } + + *found_sym = 1; + + coff_add_syminfo_data (state, sdata); + } + + backtrace_release_view (state, §s_view, error_callback, data); + sects_view_valid = 0; + backtrace_release_view (state, &syms_view, error_callback, data); + syms_view_valid = 0; + + /* Read all the debug sections in a single view, since they are + probably adjacent in the file. We never release this view. */ + + min_offset = 0; + max_offset = 0; + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + off_t end; + + if (sections[i].size == 0) + continue; + if (min_offset == 0 || sections[i].offset < min_offset) + min_offset = sections[i].offset; + end = sections[i].offset + sections[i].size; + if (end > max_offset) + max_offset = end; + } + if (min_offset == 0 || max_offset == 0) + { + if (!backtrace_close (descriptor, error_callback, data)) + goto fail; + *fileline_fn = coff_nodebug; + return 1; + } + + if (!backtrace_get_view (state, descriptor, min_offset, + max_offset - min_offset, + error_callback, data, &debug_view)) + goto fail; + debug_view_valid = 1; + + /* We've read all we need from the executable. */ + if (!backtrace_close (descriptor, error_callback, data)) + goto fail; + descriptor = -1; + + for (i = 0; i < (int) DEBUG_MAX; ++i) + { + if (sections[i].size == 0) + sections[i].data = NULL; + else + sections[i].data = ((const unsigned char *) debug_view.data + + (sections[i].offset - min_offset)); + } + + if (!backtrace_dwarf_add (state, /* base_address */ 0, + sections[DEBUG_INFO].data, + sections[DEBUG_INFO].size, + sections[DEBUG_LINE].data, + sections[DEBUG_LINE].size, + sections[DEBUG_ABBREV].data, + sections[DEBUG_ABBREV].size, + sections[DEBUG_RANGES].data, + sections[DEBUG_RANGES].size, + sections[DEBUG_STR].data, + sections[DEBUG_STR].size, + 0, /* FIXME */ + error_callback, data, fileline_fn)) + goto fail; + + *found_dwarf = 1; + + return 1; + + fail: + if (sects_view_valid) + backtrace_release_view (state, §s_view, error_callback, data); + if (str_view_valid) + backtrace_release_view (state, &str_view, error_callback, data); + if (syms_view_valid) + backtrace_release_view (state, &syms_view, error_callback, data); + if (debug_view_valid) + backtrace_release_view (state, &debug_view, error_callback, data); + if (descriptor != -1) + backtrace_close (descriptor, error_callback, data); + return 0; +} + +/* Initialize the backtrace data we need from an ELF executable. At + the ELF level, all we need to do is find the debug info + sections. */ + +int +backtrace_initialize (struct backtrace_state *state, int descriptor, + backtrace_error_callback error_callback, + void *data, fileline *fileline_fn) +{ + int ret; + int found_sym; + int found_dwarf; + fileline coff_fileline_fn; + + ret = coff_add (state, descriptor, error_callback, data, + &coff_fileline_fn, &found_sym, &found_dwarf); + if (!ret) + return 0; + + if (!state->threaded) + { + if (found_sym) + state->syminfo_fn = coff_syminfo; + else if (state->syminfo_fn == NULL) + state->syminfo_fn = coff_nosyms; + } + else + { + if (found_sym) + backtrace_atomic_store_pointer (&state->syminfo_fn, coff_syminfo); + else + __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, coff_nosyms); + } + + if (!state->threaded) + { + if (state->fileline_fn == NULL || state->fileline_fn == coff_nodebug) + *fileline_fn = coff_fileline_fn; + } + else + { + fileline current_fn; + + current_fn = backtrace_atomic_load_pointer (&state->fileline_fn); + if (current_fn == NULL || current_fn == coff_nodebug) + *fileline_fn = coff_fileline_fn; + } + + return 1; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/posix.c b/backtrace-sys-0.1.16/src/libbacktrace/posix.c new file mode 100644 index 000000000..be7357e6b --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/posix.c @@ -0,0 +1,100 @@ +/* posix.c -- POSIX file I/O routines for the backtrace library. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +/* Open a file for reading. */ + +int +backtrace_open (const char *filename, backtrace_error_callback error_callback, + void *data, int *does_not_exist) +{ + int descriptor; + + if (does_not_exist != NULL) + *does_not_exist = 0; + + descriptor = open (filename, (int) (O_RDONLY | O_BINARY | O_CLOEXEC)); + if (descriptor < 0) + { + if (does_not_exist != NULL && errno == ENOENT) + *does_not_exist = 1; + else + error_callback (data, filename, errno); + return -1; + } + +#ifdef HAVE_FCNTL + /* Set FD_CLOEXEC just in case the kernel does not support + O_CLOEXEC. It doesn't matter if this fails for some reason. + FIXME: At some point it should be safe to only do this if + O_CLOEXEC == 0. */ + fcntl (descriptor, F_SETFD, FD_CLOEXEC); +#endif + + return descriptor; +} + +/* Close DESCRIPTOR. */ + +int +backtrace_close (int descriptor, backtrace_error_callback error_callback, + void *data) +{ + if (close (descriptor) < 0) + { + error_callback (data, "close", errno); + return 0; + } + return 1; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/print.c b/backtrace-sys-0.1.16/src/libbacktrace/print.c new file mode 100644 index 000000000..73b8abc19 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/print.c @@ -0,0 +1,92 @@ +/* print.c -- Print the current backtrace. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +/* Passed to callbacks. */ + +struct print_data +{ + struct backtrace_state *state; + FILE *f; +}; + +/* Print one level of a backtrace. */ + +static int +print_callback (void *data, uintptr_t pc, const char *filename, int lineno, + const char *function) +{ + struct print_data *pdata = (struct print_data *) data; + + fprintf (pdata->f, "0x%lx %s\n\t%s:%d\n", + (unsigned long) pc, + function == NULL ? "???" : function, + filename == NULL ? "???" : filename, + lineno); + return 0; +} + +/* Print errors to stderr. */ + +static void +error_callback (void *data, const char *msg, int errnum) +{ + struct print_data *pdata = (struct print_data *) data; + + if (pdata->state->filename != NULL) + fprintf (stderr, "%s: ", pdata->state->filename); + fprintf (stderr, "libbacktrace: %s", msg); + if (errnum > 0) + fprintf (stderr, ": %s", strerror (errnum)); + fputc ('\n', stderr); +} + +/* Print a backtrace. */ + +void +backtrace_print (struct backtrace_state *state, int skip, FILE *f) +{ + struct print_data data; + + data.state = state; + data.f = f; + backtrace_full (state, skip + 1, print_callback, error_callback, + (void *) &data); +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/read.c b/backtrace-sys-0.1.16/src/libbacktrace/read.c new file mode 100644 index 000000000..33b68f843 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/read.c @@ -0,0 +1,96 @@ +/* read.c -- File views without mmap. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +/* This file implements file views when mmap is not available. */ + +/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */ + +int +backtrace_get_view (struct backtrace_state *state, int descriptor, + off_t offset, size_t size, + backtrace_error_callback error_callback, + void *data, struct backtrace_view *view) +{ + ssize_t got; + + if (lseek (descriptor, offset, SEEK_SET) < 0) + { + error_callback (data, "lseek", errno); + return 0; + } + + view->base = backtrace_alloc (state, size, error_callback, data); + if (view->base == NULL) + return 0; + view->data = view->base; + view->len = size; + + got = read (descriptor, view->base, size); + if (got < 0) + { + error_callback (data, "read", errno); + free (view->base); + return 0; + } + + if ((size_t) got < size) + { + error_callback (data, "file too short", 0); + free (view->base); + return 0; + } + + return 1; +} + +/* Release a view read by backtrace_get_view. */ + +void +backtrace_release_view (struct backtrace_state *state, + struct backtrace_view *view, + backtrace_error_callback error_callback, + void *data) +{ + backtrace_free (state, view->base, view->len, error_callback, data); + view->data = NULL; + view->base = NULL; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/simple.c b/backtrace-sys-0.1.16/src/libbacktrace/simple.c new file mode 100644 index 000000000..493fd6de7 --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/simple.c @@ -0,0 +1,108 @@ +/* simple.c -- The backtrace_simple function. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include "unwind.h" +#include "backtrace.h" + +/* The simple_backtrace routine. */ + +/* Data passed through _Unwind_Backtrace. */ + +struct backtrace_simple_data +{ + /* Number of frames to skip. */ + int skip; + /* Library state. */ + struct backtrace_state *state; + /* Callback routine. */ + backtrace_simple_callback callback; + /* Error callback routine. */ + backtrace_error_callback error_callback; + /* Data to pass to callback routine. */ + void *data; + /* Value to return from backtrace. */ + int ret; +}; + +/* Unwind library callback routine. This is passd to + _Unwind_Backtrace. */ + +static _Unwind_Reason_Code +simple_unwind (struct _Unwind_Context *context, void *vdata) +{ + struct backtrace_simple_data *bdata = (struct backtrace_simple_data *) vdata; + uintptr_t pc; + int ip_before_insn = 0; + +#ifdef HAVE_GETIPINFO + pc = _Unwind_GetIPInfo (context, &ip_before_insn); +#else + pc = _Unwind_GetIP (context); +#endif + + if (bdata->skip > 0) + { + --bdata->skip; + return _URC_NO_REASON; + } + + if (!ip_before_insn) + --pc; + + bdata->ret = bdata->callback (bdata->data, pc); + + if (bdata->ret != 0) + return _URC_END_OF_STACK; + + return _URC_NO_REASON; +} + +/* Get a simple stack backtrace. */ + +int +backtrace_simple (struct backtrace_state *state, int skip, + backtrace_simple_callback callback, + backtrace_error_callback error_callback, void *data) +{ + struct backtrace_simple_data bdata; + + bdata.skip = skip + 1; + bdata.state = state; + bdata.callback = callback; + bdata.error_callback = error_callback; + bdata.data = data; + bdata.ret = 0; + _Unwind_Backtrace (simple_unwind, &bdata); + return bdata.ret; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/sort.c b/backtrace-sys-0.1.16/src/libbacktrace/sort.c new file mode 100644 index 000000000..f352fca5e --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/sort.c @@ -0,0 +1,108 @@ +/* sort.c -- Sort without allocating memory + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include + +#include "backtrace.h" +#include "internal.h" + +/* The GNU glibc version of qsort allocates memory, which we must not + do if we are invoked by a signal handler. So provide our own + sort. */ + +static void +swap (char *a, char *b, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++, a++, b++) + { + char t; + + t = *a; + *a = *b; + *b = t; + } +} + +void +backtrace_qsort (void *basearg, size_t count, size_t size, + int (*compar) (const void *, const void *)) +{ + char *base = (char *) basearg; + size_t i; + size_t mid; + + tail_recurse: + if (count < 2) + return; + + /* The symbol table and DWARF tables, which is all we use this + routine for, tend to be roughly sorted. Pick the middle element + in the array as our pivot point, so that we are more likely to + cut the array in half for each recursion step. */ + swap (base, base + (count / 2) * size, size); + + mid = 0; + for (i = 1; i < count; i++) + { + if ((*compar) (base, base + i * size) > 0) + { + ++mid; + if (i != mid) + swap (base + mid * size, base + i * size, size); + } + } + + if (mid > 0) + swap (base, base + mid * size, size); + + /* Recurse with the smaller array, loop with the larger one. That + ensures that our maximum stack depth is log count. */ + if (2 * mid < count) + { + backtrace_qsort (base, mid, size, compar); + base += (mid + 1) * size; + count -= mid + 1; + goto tail_recurse; + } + else + { + backtrace_qsort (base + (mid + 1) * size, count - (mid + 1), + size, compar); + count = mid; + goto tail_recurse; + } +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/state.c b/backtrace-sys-0.1.16/src/libbacktrace/state.c new file mode 100644 index 000000000..361a3963c --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/state.c @@ -0,0 +1,72 @@ +/* state.c -- Create the backtrace state. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include + +#include "backtrace.h" +#include "backtrace-supported.h" +#include "internal.h" + +/* Create the backtrace state. This will then be passed to all the + other routines. */ + +struct backtrace_state * +backtrace_create_state (const char *filename, int threaded, + backtrace_error_callback error_callback, + void *data) +{ + struct backtrace_state init_state; + struct backtrace_state *state; + +#ifndef HAVE_SYNC_FUNCTIONS + if (threaded) + { + error_callback (data, "backtrace library does not support threads", 0); + return NULL; + } +#endif + + memset (&init_state, 0, sizeof init_state); + init_state.filename = filename; + init_state.threaded = threaded; + + state = ((struct backtrace_state *) + backtrace_alloc (&init_state, sizeof *state, error_callback, data)); + if (state == NULL) + return NULL; + *state = init_state; + + return state; +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/stest.c b/backtrace-sys-0.1.16/src/libbacktrace/stest.c new file mode 100644 index 000000000..7a0b06d3e --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/stest.c @@ -0,0 +1,137 @@ +/* stest.c -- Test for libbacktrace internal sort function + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include +#include +#include +#include + +#include "backtrace.h" +#include "internal.h" + +/* Test the local qsort implementation. */ + +#define MAX 10 + +struct test +{ + size_t count; + int input[MAX]; + int output[MAX]; +}; + +static struct test tests[] = + { + { + 10, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } + }, + { + 9, + { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9 } + }, + { + 10, + { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, + }, + { + 9, + { 9, 8, 7, 6, 5, 4, 3, 2, 1 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + }, + { + 10, + { 2, 4, 6, 8, 10, 1, 3, 5, 7, 9 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, + }, + { + 5, + { 4, 5, 3, 1, 2 }, + { 1, 2, 3, 4, 5 }, + }, + { + 5, + { 1, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 1 }, + }, + { + 5, + { 1, 1, 2, 1, 1 }, + { 1, 1, 1, 1, 2 }, + }, + { + 5, + { 2, 1, 1, 1, 1 }, + { 1, 1, 1, 1, 2 }, + }, + }; + +static int +compare (const void *a, const void *b) +{ + const int *ai = (const int *) a; + const int *bi = (const int *) b; + + return *ai - *bi; +} + +int +main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) +{ + int failures; + size_t i; + int a[MAX]; + + failures = 0; + for (i = 0; i < sizeof tests / sizeof tests[0]; i++) + { + memcpy (a, tests[i].input, tests[i].count * sizeof (int)); + backtrace_qsort (a, tests[i].count, sizeof (int), compare); + if (memcmp (a, tests[i].output, tests[i].count * sizeof (int)) != 0) + { + size_t j; + + fprintf (stderr, "test %d failed:", (int) i); + for (j = 0; j < tests[i].count; j++) + fprintf (stderr, " %d", a[j]); + fprintf (stderr, "\n"); + ++failures; + } + } + + exit (failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS); +} diff --git a/backtrace-sys-0.1.16/src/libbacktrace/unknown.c b/backtrace-sys-0.1.16/src/libbacktrace/unknown.c new file mode 100644 index 000000000..8afe65b3f --- /dev/null +++ b/backtrace-sys-0.1.16/src/libbacktrace/unknown.c @@ -0,0 +1,64 @@ +/* unknown.c -- used when backtrace configury does not know file format. + Copyright (C) 2012-2016 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Google. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + (1) Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + (2) Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + (3) The name of the author may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. */ + +#include "config.h" + +#include + +#include "backtrace.h" +#include "internal.h" + +/* A trivial routine that always fails to find fileline data. */ + +static int +unknown_fileline (struct backtrace_state *state ATTRIBUTE_UNUSED, + uintptr_t pc, backtrace_full_callback callback, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data) + +{ + return callback (data, pc, NULL, 0, NULL); +} + +/* Initialize the backtrace data when we don't know how to read the + debug info. */ + +int +backtrace_initialize (struct backtrace_state *state ATTRIBUTE_UNUSED, + int descriptor ATTRIBUTE_UNUSED, + backtrace_error_callback error_callback ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED, fileline *fileline_fn) +{ + state->fileline_data = NULL; + *fileline_fn = unknown_fileline; + return 1; +} diff --git a/backtrace-sys-0.1.16/symbol-map b/backtrace-sys-0.1.16/symbol-map new file mode 100644 index 000000000..fbadc7369 --- /dev/null +++ b/backtrace-sys-0.1.16/symbol-map @@ -0,0 +1,18 @@ +backtrace_full __rbt_backtrace_full +backtrace_dwarf_add __rbt_backtrace_dwarf_add +backtrace_initialize __rbt_backtrace_initialize +backtrace_pcinfo __rbt_backtrace_pcinfo +backtrace_syminfo __rbt_backtrace_syminfo +backtrace_get_view __rbt_backtrace_get_view +backtrace_release_view __rbt_backtrace_release_view +backtrace_alloc __rbt_backtrace_alloc +backtrace_free __rbt_backtrace_free +backtrace_vector_finish __rbt_backtrace_vector_finish +backtrace_vector_grow __rbt_backtrace_vector_grow +backtrace_vector_release __rbt_backtrace_vector_release +backtrace_close __rbt_backtrace_close +backtrace_open __rbt_backtrace_open +backtrace_print __rbt_backtrace_print +backtrace_simple __rbt_backtrace_simple +backtrace_qsort __rbt_backtrace_qsort +backtrace_create_state __rbt_backtrace_create_state diff --git a/bitflags-0.9.1/.cargo-checksum.json b/bitflags-0.9.1/.cargo-checksum.json new file mode 100644 index 000000000..a4e2f84db --- /dev/null +++ b/bitflags-0.9.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"} \ No newline at end of file diff --git a/bitflags-0.9.1/.travis.yml b/bitflags-0.9.1/.travis.yml new file mode 100644 index 000000000..5eb31843a --- /dev/null +++ b/bitflags-0.9.1/.travis.yml @@ -0,0 +1,29 @@ +os: + - linux + - osx +language: rust +rust: + - stable + - beta + - nightly +sudo: false +before_script: + - pip install -v 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH + - if [[ -e ~/Library/Python/2.7/bin ]]; then export PATH=~/Library/Python/2.7/bin:$PATH; fi +script: + - cargo build --verbose + - cargo test --verbose + - travis-cargo --only nightly test + - cargo doc --no-deps +after_success: + - travis-cargo --only nightly doc-upload +env: + global: + - TRAVIS_CARGO_NIGHTLY_FEATURE=unstable_testing + - secure: "DoZ8g8iPs+X3xEEucke0Ae02JbkQ1qd1SSv/L2aQqxULmREtRcbzRauhiT+ToQO5Ft1Lul8uck14nPfs4gMr/O3jFFBhEBVpSlbkJx7eNL3kwUdp95UNroA8I43xPN/nccJaHDN6TMTD3+uajTQTje2SyzOQP+1gvdKg17kguvE=" + + + +notifications: + email: + on_success: never diff --git a/bitflags-0.9.1/Cargo.toml b/bitflags-0.9.1/Cargo.toml new file mode 100644 index 000000000..8ac9adbfc --- /dev/null +++ b/bitflags-0.9.1/Cargo.toml @@ -0,0 +1,31 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bitflags" +version = "0.9.1" +authors = ["The Rust Project Developers"] +description = "A macro to generate structures which behave like bitflags.\n" +homepage = "https://github.com/rust-lang-nursery/bitflags" +documentation = "https://docs.rs/bitflags" +readme = "README.md" +keywords = ["bit", "bitmask", "bitflags"] +categories = ["no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang-nursery/bitflags" + +[features] +example_generated = [] +unstable_testing = [] +default = ["example_generated"] +[badges.travis-ci] +repository = "rust-lang-nursery/bitflags" diff --git a/bitflags-0.9.1/LICENSE-APACHE b/bitflags-0.9.1/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/bitflags-0.9.1/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/bitflags-0.9.1/LICENSE-MIT b/bitflags-0.9.1/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/bitflags-0.9.1/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/bitflags-0.9.1/README.md b/bitflags-0.9.1/README.md new file mode 100644 index 000000000..714ca9d9e --- /dev/null +++ b/bitflags-0.9.1/README.md @@ -0,0 +1,24 @@ +bitflags +======== + +A Rust macro to generate structures which behave like a set of bitflags + +[![Build Status](https://travis-ci.org/rust-lang-nursery/bitflags.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/bitflags) + +[Documentation](https://docs.rs/bitflags) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +bitflags = "0.9" +``` + +and this to your crate root: + +```rust +#[macro_use] +extern crate bitflags; +``` diff --git a/bitflags-0.9.1/src/example_generated.rs b/bitflags-0.9.1/src/example_generated.rs new file mode 100644 index 000000000..05b99e8f0 --- /dev/null +++ b/bitflags-0.9.1/src/example_generated.rs @@ -0,0 +1,16 @@ +//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS +//! CRATE**. + +bitflags! { + /// This is the same `Flags` struct defined in the [crate level example](../index.html#example). + /// Note that this struct is just for documentation purposes only, it must not be used outside + /// this crate. + pub struct Flags: u32 { + const FLAG_A = 0b00000001; + const FLAG_B = 0b00000010; + const FLAG_C = 0b00000100; + const FLAG_ABC = FLAG_A.bits + | FLAG_B.bits + | FLAG_C.bits; + } +} diff --git a/bitflags-0.9.1/src/lib.rs b/bitflags-0.9.1/src/lib.rs new file mode 100644 index 000000000..5840643a8 --- /dev/null +++ b/bitflags-0.9.1/src/lib.rs @@ -0,0 +1,990 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A typesafe bitmask flag generator useful for sets of C-style bitmask flags. +//! It can be used for creating typesafe wrappers around C APIs. +//! +//! The `bitflags!` macro generates a `struct` that manages a set of flags. The +//! flags should only be defined for integer types, otherwise unexpected type +//! errors may occur at compile time. +//! +//! # Example +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const FLAG_A = 0b00000001; +//! const FLAG_B = 0b00000010; +//! const FLAG_C = 0b00000100; +//! const FLAG_ABC = FLAG_A.bits +//! | FLAG_B.bits +//! | FLAG_C.bits; +//! } +//! } +//! +//! fn main() { +//! let e1 = FLAG_A | FLAG_C; +//! let e2 = FLAG_B | FLAG_C; +//! assert_eq!((e1 | e2), FLAG_ABC); // union +//! assert_eq!((e1 & e2), FLAG_C); // intersection +//! assert_eq!((e1 - e2), FLAG_A); // set difference +//! assert_eq!(!e2, FLAG_A); // set complement +//! } +//! ``` +//! +//! See [`example_generated::Flags`](./example_generated/struct.Flags.html) for documentation of code +//! generated by the above `bitflags!` expansion. +//! +//! The generated `struct`s can also be extended with type and trait +//! implementations: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! use std::fmt; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const FLAG_A = 0b00000001; +//! const FLAG_B = 0b00000010; +//! } +//! } +//! +//! impl Flags { +//! pub fn clear(&mut self) { +//! self.bits = 0; // The `bits` field can be accessed from within the +//! // same module where the `bitflags!` macro was invoked. +//! } +//! } +//! +//! impl fmt::Display for Flags { +//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +//! write!(f, "hi!") +//! } +//! } +//! +//! fn main() { +//! let mut flags = FLAG_A | FLAG_B; +//! flags.clear(); +//! assert!(flags.is_empty()); +//! assert_eq!(format!("{}", flags), "hi!"); +//! assert_eq!(format!("{:?}", FLAG_A | FLAG_B), "FLAG_A | FLAG_B"); +//! assert_eq!(format!("{:?}", FLAG_B), "FLAG_B"); +//! } +//! ``` +//! +//! # Visibility +//! +//! The generated struct and its associated flag constants are not exported +//! out of the current module by default. A definition can be exported out of +//! the current module by adding `pub` before `flags`: +//! +//! ```ignore +//! #[macro_use] +//! extern crate bitflags; +//! +//! mod example { +//! bitflags! { +//! pub struct Flags1: u32 { +//! const FLAG_A = 0b00000001; +//! } +//! } +//! bitflags! { +//! struct Flags2: u32 { +//! const FLAG_B = 0b00000010; +//! } +//! } +//! } +//! +//! fn main() { +//! let flag1 = example::FLAG_A; +//! let flag2 = example::FLAG_B; // error: const `FLAG_B` is private +//! } +//! ``` +//! +//! # Attributes +//! +//! Attributes can be attached to the generated `struct` by placing them +//! before the `flags` keyword. +//! +//! # Trait implementations +//! +//! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash` +//! traits automatically derived for the `struct` using the `derive` attribute. +//! Additional traits can be derived by providing an explicit `derive` +//! attribute on `flags`. +//! +//! The `Extend` and `FromIterator` traits are implemented for the `struct`, +//! too: `Extend` adds the union of the instances of the `struct` iterated over, +//! while `FromIterator` calculates the union. +//! +//! The `Binary`, `Debug`, `LowerExp`, `Octal` and `UpperExp` trait is also +//! implemented by displaying the bits value of the internal struct. +//! +//! ## Operators +//! +//! The following operator traits are implemented for the generated `struct`: +//! +//! - `BitOr` and `BitOrAssign`: union +//! - `BitAnd` and `BitAndAssign`: intersection +//! - `BitXor` and `BitXorAssign`: toggle +//! - `Sub` and `SubAssign`: set difference +//! - `Not`: set complement +//! +//! # Methods +//! +//! The following methods are defined for the generated `struct`: +//! +//! - `empty`: an empty set of flags +//! - `all`: the set of all flags +//! - `bits`: the raw value of the flags currently stored +//! - `from_bits`: convert from underlying bit representation, unless that +//! representation contains bits that do not correspond to a flag +//! - `from_bits_truncate`: convert from underlying bit representation, dropping +//! any bits that do not correspond to flags +//! - `is_empty`: `true` if no flags are currently stored +//! - `is_all`: `true` if all flags are currently set +//! - `intersects`: `true` if there are flags common to both `self` and `other` +//! - `contains`: `true` all of the flags in `other` are contained within `self` +//! - `insert`: inserts the specified flags in-place +//! - `remove`: removes the specified flags in-place +//! - `toggle`: the specified flags will be inserted if not present, and removed +//! if they are. +//! +//! ## Default +//! +//! The `Default` trait is not automatically implemented for the generated struct. +//! +//! If your default value is equal to `0` (which is the same value as calling `empty()` +//! on the generated struct), you can simply derive `Default`: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! // Results in default value with bits: 0 +//! #[derive(Default)] +//! struct Flags: u32 { +//! const FLAG_A = 0b00000001; +//! const FLAG_B = 0b00000010; +//! const FLAG_C = 0b00000100; +//! } +//! } +//! +//! fn main() { +//! let derived_default: Flags = Default::default(); +//! assert_eq!(derived_default.bits(), 0); +//! } +//! ``` +//! +//! If your default value is not equal to `0` you need to implement `Default` yourself: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const FLAG_A = 0b00000001; +//! const FLAG_B = 0b00000010; +//! const FLAG_C = 0b00000100; +//! } +//! } +//! +//! // explicit `Default` implementation +//! impl Default for Flags { +//! fn default() -> Flags { +//! FLAG_A | FLAG_C +//! } +//! } +//! +//! fn main() { +//! let implemented_default: Flags = Default::default(); +//! assert_eq!(implemented_default, (FLAG_A | FLAG_C)); +//! } +//! ``` + +#![no_std] + +#![doc(html_root_url = "https://docs.rs/bitflags/0.9.1")] +// When compiled for the rustc compiler itself we want to make sure that this is +// an unstable crate. +#![cfg_attr(rustbuild, feature(staged_api))] +#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] + +#[cfg(test)] +#[macro_use] +extern crate std; + +// Re-export libstd/libcore using an alias so that the macros can work in no_std +// crates while remaining compatible with normal crates. +#[doc(hidden)] +pub extern crate core as _core; + +/// The macro used to generate the flag structure. +/// +/// See the [crate level docs](../bitflags/index.html) for complete documentation. +/// +/// # Example +/// +/// ``` +/// #[macro_use] +/// extern crate bitflags; +/// +/// bitflags! { +/// struct Flags: u32 { +/// const FLAG_A = 0b00000001; +/// const FLAG_B = 0b00000010; +/// const FLAG_C = 0b00000100; +/// const FLAG_ABC = FLAG_A.bits +/// | FLAG_B.bits +/// | FLAG_C.bits; +/// } +/// } +/// +/// fn main() { +/// let e1 = FLAG_A | FLAG_C; +/// let e2 = FLAG_B | FLAG_C; +/// assert_eq!((e1 | e2), FLAG_ABC); // union +/// assert_eq!((e1 & e2), FLAG_C); // intersection +/// assert_eq!((e1 - e2), FLAG_A); // set difference +/// assert_eq!(!e2, FLAG_A); // set complement +/// } +/// ``` +/// +/// The generated `struct`s can also be extended with type and trait +/// implementations: +/// +/// ``` +/// #[macro_use] +/// extern crate bitflags; +/// +/// use std::fmt; +/// +/// bitflags! { +/// struct Flags: u32 { +/// const FLAG_A = 0b00000001; +/// const FLAG_B = 0b00000010; +/// } +/// } +/// +/// impl Flags { +/// pub fn clear(&mut self) { +/// self.bits = 0; // The `bits` field can be accessed from within the +/// // same module where the `bitflags!` macro was invoked. +/// } +/// } +/// +/// impl fmt::Display for Flags { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "hi!") +/// } +/// } +/// +/// fn main() { +/// let mut flags = FLAG_A | FLAG_B; +/// flags.clear(); +/// assert!(flags.is_empty()); +/// assert_eq!(format!("{}", flags), "hi!"); +/// assert_eq!(format!("{:?}", FLAG_A | FLAG_B), "FLAG_A | FLAG_B"); +/// assert_eq!(format!("{:?}", FLAG_B), "FLAG_B"); +/// } +/// ``` +#[macro_export] +macro_rules! bitflags { + ($(#[$attr:meta])* pub struct $BitFlags:ident: $T:ty { + $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr;)+ + }) => { + #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] + $(#[$attr])* + pub struct $BitFlags { + bits: $T, + } + + $($(#[$Flag_attr])* pub const $Flag: $BitFlags = $BitFlags { bits: $value };)+ + + __impl_bitflags! { + struct $BitFlags: $T { + $($(#[$Flag_attr])* const $Flag = $value;)+ + } + } + }; + ($(#[$attr:meta])* struct $BitFlags:ident: $T:ty { + $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr;)+ + }) => { + #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] + $(#[$attr])* + struct $BitFlags { + bits: $T, + } + + $($(#[$Flag_attr])* const $Flag: $BitFlags = $BitFlags { bits: $value };)+ + + __impl_bitflags! { + struct $BitFlags: $T { + $($(#[$Flag_attr])* const $Flag = $value;)+ + } + } + + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! __impl_bitflags { + (struct $BitFlags:ident: $T:ty { + $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr;)+ + }) => { + impl $crate::_core::fmt::Debug for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + // This convoluted approach is to handle #[cfg]-based flag + // omission correctly. For example it needs to support: + // + // #[cfg(unix)] const A: Flag = /* ... */; + // #[cfg(windows)] const B: Flag = /* ... */; + + // Unconditionally define a check for every flag, even disabled + // ones. + #[allow(non_snake_case)] + trait __BitFlags { + $( + fn $Flag(&self) -> bool { false } + )+ + } + + // Conditionally override the check for just those flags that + // are not #[cfg]ed away. + impl __BitFlags for $BitFlags { + $( + $(#[$Flag_attr])* + fn $Flag(&self) -> bool { + self.bits & $Flag.bits == $Flag.bits + } + )+ + } + + let mut first = true; + $( + if <$BitFlags as __BitFlags>::$Flag(self) { + if !first { + try!(f.write_str(" | ")); + } + first = false; + try!(f.write_str(stringify!($Flag))); + } + )+ + if first { + try!(f.write_str("(empty)")); + } + Ok(()) + } + } + impl $crate::_core::fmt::Binary for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::Binary::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::Octal for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::Octal::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::LowerHex for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::LowerHex::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::UpperHex for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::UpperHex::fmt(&self.bits, f) + } + } + + #[allow(dead_code)] + impl $BitFlags { + /// Returns an empty set of flags. + #[inline] + pub fn empty() -> $BitFlags { + $BitFlags { bits: 0 } + } + + /// Returns the set containing all flags. + #[inline] + pub fn all() -> $BitFlags { + // See `Debug::fmt` for why this approach is taken. + #[allow(non_snake_case)] + trait __BitFlags { + $( + fn $Flag() -> $T { 0 } + )+ + } + impl __BitFlags for $BitFlags { + $( + $(#[$Flag_attr])* + fn $Flag() -> $T { $Flag.bits } + )+ + } + $BitFlags { bits: $(<$BitFlags as __BitFlags>::$Flag())|+ } + } + + /// Returns the raw value of the flags currently stored. + #[inline] + pub fn bits(&self) -> $T { + self.bits + } + + /// Convert from underlying bit representation, unless that + /// representation contains bits that do not correspond to a flag. + #[inline] + pub fn from_bits(bits: $T) -> $crate::_core::option::Option<$BitFlags> { + if (bits & !$BitFlags::all().bits()) == 0 { + $crate::_core::option::Option::Some($BitFlags { bits: bits }) + } else { + $crate::_core::option::Option::None + } + } + + /// Convert from underlying bit representation, dropping any bits + /// that do not correspond to flags. + #[inline] + pub fn from_bits_truncate(bits: $T) -> $BitFlags { + $BitFlags { bits: bits } & $BitFlags::all() + } + + /// Returns `true` if no flags are currently stored. + #[inline] + pub fn is_empty(&self) -> bool { + *self == $BitFlags::empty() + } + + /// Returns `true` if all flags are currently set. + #[inline] + pub fn is_all(&self) -> bool { + *self == $BitFlags::all() + } + + /// Returns `true` if there are flags common to both `self` and `other`. + #[inline] + pub fn intersects(&self, other: $BitFlags) -> bool { + !(*self & other).is_empty() + } + + /// Returns `true` all of the flags in `other` are contained within `self`. + #[inline] + pub fn contains(&self, other: $BitFlags) -> bool { + (*self & other) == other + } + + /// Inserts the specified flags in-place. + #[inline] + pub fn insert(&mut self, other: $BitFlags) { + self.bits |= other.bits; + } + + /// Removes the specified flags in-place. + #[inline] + pub fn remove(&mut self, other: $BitFlags) { + self.bits &= !other.bits; + } + + /// Toggles the specified flags in-place. + #[inline] + pub fn toggle(&mut self, other: $BitFlags) { + self.bits ^= other.bits; + } + + /// Inserts or removes the specified flags depending on the passed value. + #[inline] + pub fn set(&mut self, other: $BitFlags, value: bool) { + if value { + self.insert(other); + } else { + self.remove(other); + } + } + } + + impl $crate::_core::ops::BitOr for $BitFlags { + type Output = $BitFlags; + + /// Returns the union of the two sets of flags. + #[inline] + fn bitor(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits | other.bits } + } + } + + impl $crate::_core::ops::BitOrAssign for $BitFlags { + + /// Adds the set of flags. + #[inline] + fn bitor_assign(&mut self, other: $BitFlags) { + self.bits |= other.bits; + } + } + + impl $crate::_core::ops::BitXor for $BitFlags { + type Output = $BitFlags; + + /// Returns the left flags, but with all the right flags toggled. + #[inline] + fn bitxor(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits ^ other.bits } + } + } + + impl $crate::_core::ops::BitXorAssign for $BitFlags { + + /// Toggles the set of flags. + #[inline] + fn bitxor_assign(&mut self, other: $BitFlags) { + self.bits ^= other.bits; + } + } + + impl $crate::_core::ops::BitAnd for $BitFlags { + type Output = $BitFlags; + + /// Returns the intersection between the two sets of flags. + #[inline] + fn bitand(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & other.bits } + } + } + + impl $crate::_core::ops::BitAndAssign for $BitFlags { + + /// Disables all flags disabled in the set. + #[inline] + fn bitand_assign(&mut self, other: $BitFlags) { + self.bits &= other.bits; + } + } + + impl $crate::_core::ops::Sub for $BitFlags { + type Output = $BitFlags; + + /// Returns the set difference of the two sets of flags. + #[inline] + fn sub(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & !other.bits } + } + } + + impl $crate::_core::ops::SubAssign for $BitFlags { + + /// Disables all flags enabled in the set. + #[inline] + fn sub_assign(&mut self, other: $BitFlags) { + self.bits &= !other.bits; + } + } + + impl $crate::_core::ops::Not for $BitFlags { + type Output = $BitFlags; + + /// Returns the complement of this set of flags. + #[inline] + fn not(self) -> $BitFlags { + $BitFlags { bits: !self.bits } & $BitFlags::all() + } + } + + impl $crate::_core::iter::Extend<$BitFlags> for $BitFlags { + fn extend>(&mut self, iterator: T) { + for item in iterator { + self.insert(item) + } + } + } + + impl $crate::_core::iter::FromIterator<$BitFlags> for $BitFlags { + fn from_iter>(iterator: T) -> $BitFlags { + let mut result = Self::empty(); + result.extend(iterator); + result + } + } + }; +} + +#[cfg(feature = "example_generated")] +pub mod example_generated; + +#[cfg(test)] +#[allow(non_upper_case_globals, dead_code)] +mod tests { + use std::hash::{Hash, Hasher}; + use std::collections::hash_map::DefaultHasher; + + bitflags! { + #[doc = "> The first principle is that you must not fool yourself — and"] + #[doc = "> you are the easiest person to fool."] + #[doc = "> "] + #[doc = "> - Richard Feynman"] + struct Flags: u32 { + const FlagA = 0b00000001; + #[doc = " macros are way better at generating code than trans is"] + const FlagB = 0b00000010; + const FlagC = 0b00000100; + #[doc = "* cmr bed"] + #[doc = "* strcat table"] + #[doc = " wait what?"] + const FlagABC = FlagA.bits + | FlagB.bits + | FlagC.bits; + } + } + + bitflags! { + struct _CfgFlags: u32 { + #[cfg(windows)] + const _CfgA = 0b01; + #[cfg(unix)] + const _CfgB = 0b01; + #[cfg(windows)] + const _CfgC = _CfgA.bits | 0b10; + } + } + + bitflags! { + struct AnotherSetOfFlags: i8 { + const AnotherFlag = -1_i8; + } + } + + bitflags! { + struct LongFlags: u32 { + const LongFlagA = 0b1111111111111111; + } + } + + #[test] + fn test_bits(){ + assert_eq!(Flags::empty().bits(), 0b00000000); + assert_eq!(FlagA.bits(), 0b00000001); + assert_eq!(FlagABC.bits(), 0b00000111); + + assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00); + assert_eq!(AnotherFlag.bits(), !0_i8); + } + + #[test] + fn test_from_bits() { + assert_eq!(Flags::from_bits(0), Some(Flags::empty())); + assert_eq!(Flags::from_bits(0b1), Some(FlagA)); + assert_eq!(Flags::from_bits(0b10), Some(FlagB)); + assert_eq!(Flags::from_bits(0b11), Some(FlagA | FlagB)); + assert_eq!(Flags::from_bits(0b1000), None); + + assert_eq!(AnotherSetOfFlags::from_bits(!0_i8), Some(AnotherFlag)); + } + + #[test] + fn test_from_bits_truncate() { + assert_eq!(Flags::from_bits_truncate(0), Flags::empty()); + assert_eq!(Flags::from_bits_truncate(0b1), FlagA); + assert_eq!(Flags::from_bits_truncate(0b10), FlagB); + assert_eq!(Flags::from_bits_truncate(0b11), (FlagA | FlagB)); + assert_eq!(Flags::from_bits_truncate(0b1000), Flags::empty()); + assert_eq!(Flags::from_bits_truncate(0b1001), FlagA); + + assert_eq!(AnotherSetOfFlags::from_bits_truncate(0_i8), AnotherSetOfFlags::empty()); + } + + #[test] + fn test_is_empty(){ + assert!(Flags::empty().is_empty()); + assert!(!FlagA.is_empty()); + assert!(!FlagABC.is_empty()); + + assert!(!AnotherFlag.is_empty()); + } + + #[test] + fn test_is_all() { + assert!(Flags::all().is_all()); + assert!(!FlagA.is_all()); + assert!(FlagABC.is_all()); + + assert!(AnotherFlag.is_all()); + } + + #[test] + fn test_two_empties_do_not_intersect() { + let e1 = Flags::empty(); + let e2 = Flags::empty(); + assert!(!e1.intersects(e2)); + + assert!(AnotherFlag.intersects(AnotherFlag)); + } + + #[test] + fn test_empty_does_not_intersect_with_full() { + let e1 = Flags::empty(); + let e2 = FlagABC; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_disjoint_intersects() { + let e1 = FlagA; + let e2 = FlagB; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_overlapping_intersects() { + let e1 = FlagA; + let e2 = FlagA | FlagB; + assert!(e1.intersects(e2)); + } + + #[test] + fn test_contains() { + let e1 = FlagA; + let e2 = FlagA | FlagB; + assert!(!e1.contains(e2)); + assert!(e2.contains(e1)); + assert!(FlagABC.contains(e2)); + + assert!(AnotherFlag.contains(AnotherFlag)); + } + + #[test] + fn test_insert(){ + let mut e1 = FlagA; + let e2 = FlagA | FlagB; + e1.insert(e2); + assert_eq!(e1, e2); + + let mut e3 = AnotherSetOfFlags::empty(); + e3.insert(AnotherFlag); + assert_eq!(e3, AnotherFlag); + } + + #[test] + fn test_remove(){ + let mut e1 = FlagA | FlagB; + let e2 = FlagA | FlagC; + e1.remove(e2); + assert_eq!(e1, FlagB); + + let mut e3 = AnotherFlag; + e3.remove(AnotherFlag); + assert_eq!(e3, AnotherSetOfFlags::empty()); + } + + #[test] + fn test_operators() { + let e1 = FlagA | FlagC; + let e2 = FlagB | FlagC; + assert_eq!((e1 | e2), FlagABC); // union + assert_eq!((e1 & e2), FlagC); // intersection + assert_eq!((e1 - e2), FlagA); // set difference + assert_eq!(!e2, FlagA); // set complement + assert_eq!(e1 ^ e2, FlagA | FlagB); // toggle + let mut e3 = e1; + e3.toggle(e2); + assert_eq!(e3, FlagA | FlagB); + + let mut m4 = AnotherSetOfFlags::empty(); + m4.toggle(AnotherSetOfFlags::empty()); + assert_eq!(m4, AnotherSetOfFlags::empty()); + } + + #[test] + fn test_set() { + let mut e1 = FlagA | FlagC; + e1.set(FlagB, true); + e1.set(FlagC, false); + + assert_eq!(e1, FlagA | FlagB); + } + + #[test] + fn test_assignment_operators() { + let mut m1 = Flags::empty(); + let e1 = FlagA | FlagC; + // union + m1 |= FlagA; + assert_eq!(m1, FlagA); + // intersection + m1 &= e1; + assert_eq!(m1, FlagA); + // set difference + m1 -= m1; + assert_eq!(m1, Flags::empty()); + // toggle + m1 ^= e1; + assert_eq!(m1, e1); + } + + #[test] + fn test_extend() { + let mut flags; + + flags = Flags::empty(); + flags.extend([].iter().cloned()); + assert_eq!(flags, Flags::empty()); + + flags = Flags::empty(); + flags.extend([FlagA, FlagB].iter().cloned()); + assert_eq!(flags, FlagA | FlagB); + + flags = FlagA; + flags.extend([FlagA, FlagB].iter().cloned()); + assert_eq!(flags, FlagA | FlagB); + + flags = FlagB; + flags.extend([FlagA, FlagABC].iter().cloned()); + assert_eq!(flags, FlagABC); + } + + #[test] + fn test_from_iterator() { + assert_eq!([].iter().cloned().collect::(), Flags::empty()); + assert_eq!([FlagA, FlagB].iter().cloned().collect::(), FlagA | FlagB); + assert_eq!([FlagA, FlagABC].iter().cloned().collect::(), FlagABC); + } + + #[test] + fn test_lt() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(!(a < b) && !(b < a)); + b = FlagB; + assert!(a < b); + a = FlagC; + assert!(!(a < b) && b < a); + b = FlagC | FlagB; + assert!(a < b); + } + + #[test] + fn test_ord() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(a <= b && a >= b); + a = FlagA; + assert!(a > b && a >= b); + assert!(b < a && b <= a); + b = FlagB; + assert!(b > a && b >= a); + assert!(a < b && a <= b); + } + + fn hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + #[test] + fn test_hash() { + let mut x = Flags::empty(); + let mut y = Flags::empty(); + assert_eq!(hash(&x), hash(&y)); + x = Flags::all(); + y = FlagABC; + assert_eq!(hash(&x), hash(&y)); + } + + #[test] + fn test_debug() { + assert_eq!(format!("{:?}", FlagA | FlagB), "FlagA | FlagB"); + assert_eq!(format!("{:?}", Flags::empty()), "(empty)"); + assert_eq!(format!("{:?}", FlagABC), "FlagA | FlagB | FlagC | FlagABC"); + } + + #[test] + fn test_binary() { + assert_eq!(format!("{:b}", FlagABC), "111"); + assert_eq!(format!("{:#b}", FlagABC), "0b111"); + } + + #[test] + fn test_octal() { + assert_eq!(format!("{:o}", LongFlagA), "177777"); + assert_eq!(format!("{:#o}", LongFlagA), "0o177777"); + } + + #[test] + fn test_lowerhex() { + assert_eq!(format!("{:x}", LongFlagA), "ffff"); + assert_eq!(format!("{:#x}", LongFlagA), "0xffff"); + } + + #[test] + fn test_upperhex() { + assert_eq!(format!("{:X}", LongFlagA), "FFFF"); + assert_eq!(format!("{:#X}", LongFlagA), "0xFFFF"); + } + + mod submodule { + bitflags! { + pub struct PublicFlags: i8 { + const FlagX = 0; + } + } + bitflags! { + struct PrivateFlags: i8 { + const FlagY = 0; + } + } + + #[test] + fn test_private() { + let _ = FlagY; + } + } + + #[test] + fn test_public() { + let _ = submodule::FlagX; + } + + mod t1 { + mod foo { + pub type Bar = i32; + } + + bitflags! { + /// baz + struct Flags: foo::Bar { + const A = 0b00000001; + #[cfg(foo)] + const B = 0b00000010; + #[cfg(foo)] + const C = 0b00000010; + } + } + } + + #[test] + fn test_in_function() { + bitflags! { + struct Flags: u8 { + const A = 1; + #[cfg(any())] // false + const B = 2; + } + } + assert_eq!(Flags::all(), A); + assert_eq!(format!("{:?}", A), "A"); + } +} diff --git a/bitflags-0.9.1/tests/conflicting_trait_impls.rs b/bitflags-0.9.1/tests/conflicting_trait_impls.rs new file mode 100644 index 000000000..4704dfaa3 --- /dev/null +++ b/bitflags-0.9.1/tests/conflicting_trait_impls.rs @@ -0,0 +1,20 @@ +#![allow(dead_code)] +#![no_std] + +#[macro_use] +extern crate bitflags; + +#[allow(unused_imports)] +use core::fmt::Display; + +bitflags! { + /// baz + struct Flags: u32 { + const A = 0b00000001; + } +} + +#[test] +fn main() { + +} diff --git a/bitflags-0.9.1/tests/external.rs b/bitflags-0.9.1/tests/external.rs new file mode 100644 index 000000000..fc1c34670 --- /dev/null +++ b/bitflags-0.9.1/tests/external.rs @@ -0,0 +1,21 @@ +#![allow(dead_code)] + +#[macro_use] +extern crate bitflags; + +bitflags! { + /// baz + struct Flags: u32 { + const A = 0b00000001; + #[doc = "bar"] + const B = 0b00000010; + const C = 0b00000100; + #[doc = "foo"] + const ABC = A.bits | B.bits | C.bits; + } +} + +#[test] +fn smoke() { + assert_eq!(ABC, A | B | C); +} diff --git a/bitflags-0.9.1/tests/external_no_std.rs b/bitflags-0.9.1/tests/external_no_std.rs new file mode 100644 index 000000000..8b8c7067f --- /dev/null +++ b/bitflags-0.9.1/tests/external_no_std.rs @@ -0,0 +1,22 @@ +#![allow(dead_code)] +#![no_std] + +#[macro_use] +extern crate bitflags; + +bitflags! { + /// baz + struct Flags: u32 { + const A = 0b00000001; + #[doc = "bar"] + const B = 0b00000010; + const C = 0b00000100; + #[doc = "foo"] + const ABC = A.bits | B.bits | C.bits; + } +} + +#[test] +fn smoke() { + assert_eq!(ABC, A | B | C); +} diff --git a/bitflags-0.9.1/tests/i128_bitflags.rs b/bitflags-0.9.1/tests/i128_bitflags.rs new file mode 100644 index 000000000..acbb92782 --- /dev/null +++ b/bitflags-0.9.1/tests/i128_bitflags.rs @@ -0,0 +1,30 @@ +#![cfg(feature = "unstable_testing")] + +#![allow(dead_code, unused_imports)] +#![feature(i128_type)] + +#[macro_use] +extern crate bitflags; + +bitflags! { + /// baz + struct Flags128: u128 { + const A = 0x0000_0000_0000_0000_0000_0000_0000_0001; + const B = 0x0000_0000_0000_1000_0000_0000_0000_0000; + const C = 0x8000_0000_0000_0000_0000_0000_0000_0000; + const ABC = A.bits | B.bits | C.bits; + } +} + +#[test] +fn test_i128_bitflags() { + assert_eq!(ABC, A | B | C); + assert_eq!(A.bits, 0x0000_0000_0000_0000_0000_0000_0000_0001); + assert_eq!(B.bits, 0x0000_0000_0000_1000_0000_0000_0000_0000); + assert_eq!(C.bits, 0x8000_0000_0000_0000_0000_0000_0000_0000); + assert_eq!(ABC.bits, 0x8000_0000_0000_1000_0000_0000_0000_0001); + assert_eq!(format!("{:?}", A), "A"); + assert_eq!(format!("{:?}", B), "B"); + assert_eq!(format!("{:?}", C), "C"); + assert_eq!(format!("{:?}", ABC), "A | B | C | ABC"); +} diff --git a/bitflags-1.0.1/.cargo-checksum.json b/bitflags-1.0.1/.cargo-checksum.json new file mode 100644 index 000000000..1c6653008 --- /dev/null +++ b/bitflags-1.0.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"} \ No newline at end of file diff --git a/bitflags-1.0.1/.travis.yml b/bitflags-1.0.1/.travis.yml new file mode 100644 index 000000000..b8f7eff93 --- /dev/null +++ b/bitflags-1.0.1/.travis.yml @@ -0,0 +1,23 @@ +os: + - linux + - osx +language: rust +cache: cargo +rust: + # This version is tested to avoid unintentional bumping of the minimum supported Rust version + - 1.20.0 + - stable + - beta + - nightly +sudo: false +script: + - cargo test + - (cd ./test_suite && cargo test $([ "$TRAVIS_RUST_VERSION" = nightly ] && echo '--features unstable')) +env: + global: + - secure: "DoZ8g8iPs+X3xEEucke0Ae02JbkQ1qd1SSv/L2aQqxULmREtRcbzRauhiT+ToQO5Ft1Lul8uck14nPfs4gMr/O3jFFBhEBVpSlbkJx7eNL3kwUdp95UNroA8I43xPN/nccJaHDN6TMTD3+uajTQTje2SyzOQP+1gvdKg17kguvE=" + + +notifications: + email: + on_success: never diff --git a/bitflags-1.0.1/CHANGELOG.md b/bitflags-1.0.1/CHANGELOG.md new file mode 100644 index 000000000..4d948de0f --- /dev/null +++ b/bitflags-1.0.1/CHANGELOG.md @@ -0,0 +1,64 @@ +# 1.0.0 +- **[breaking change]** Macro now generates [associated constants](https://doc.rust-lang.org/reference/items.html#associated-constants) (#24) + +- **[breaking change]** Minimum supported version is Rust **1.20**, due to usage of associated constants + +- After being broken in 0.9, the `#[deprecated]` attribute is now supported again (#112) + +- Other improvements to unit tests and documentation (#106 and #115) + +## How to update your code to use associated constants +Assuming the following structure definition: +```rust +bitflags! { + struct Something: u8 { + const FOO = 0b01, + const BAR = 0b10 + } +} +``` +In 0.9 and older you could do: +```rust +let x = FOO.bits | BAR.bits; +``` +Now you must use: +```rust +let x = Something::FOO.bits | Something::BAR.bits; +``` + +# 0.9.1 +- Fix the implementation of `Formatting` traits when other formatting traits were present in scope (#105) + +# 0.9.0 +- **[breaking change]** Use struct keyword instead of flags to define bitflag types (#84) + +- **[breaking change]** Terminate const items with semicolons instead of commas (#87) + +- Implement the `Hex`, `Octal`, and `Binary` formatting traits (#86) + +- Printing an empty flag value with the `Debug` trait now prints "(empty)" instead of nothing (#85) + +- The `bitflags!` macro can now be used inside of a fn body, to define a type local to that function (#74) + +# 0.8.2 +- Update feature flag used when building bitflags as a dependency of the Rust toolchain + +# 0.8.1 +- Allow bitflags to be used as a dependency of the Rust toolchain + +# 0.8.0 +- Add support for the experimental `i128` and `u128` integer types (#57) +- Add set method: `flags.set(SOME_FLAG, true)` or `flags.set(SOME_FLAG, false)` (#55) + This may break code that defines its own set method + +# 0.7.1 +*(yanked)* + +# 0.7.0 +- Implement the Extend trait (#49) +- Allow definitions inside the `bitflags!` macro to refer to items imported from other modules (#51) + +# 0.6.0 +- The `no_std` feature was removed as it is now the default +- The `assignment_operators` feature was remove as it is now enabled by default +- Some clippy suggestions have been applied diff --git a/bitflags-1.0.1/Cargo.toml b/bitflags-1.0.1/Cargo.toml new file mode 100644 index 000000000..8dc548f6f --- /dev/null +++ b/bitflags-1.0.1/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "bitflags" +version = "1.0.1" +authors = ["The Rust Project Developers"] +description = "A macro to generate structures which behave like bitflags.\n" +homepage = "https://github.com/rust-lang-nursery/bitflags" +documentation = "https://docs.rs/bitflags" +readme = "README.md" +keywords = ["bit", "bitmask", "bitflags", "flags"] +categories = ["no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang-nursery/bitflags" + +[features] +default = ["example_generated"] +example_generated = [] +[badges.travis-ci] +repository = "rust-lang-nursery/bitflags" diff --git a/bitflags-1.0.1/LICENSE-APACHE b/bitflags-1.0.1/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/bitflags-1.0.1/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/bitflags-1.0.1/LICENSE-MIT b/bitflags-1.0.1/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/bitflags-1.0.1/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/bitflags-1.0.1/README.md b/bitflags-1.0.1/README.md new file mode 100644 index 000000000..0fee6069e --- /dev/null +++ b/bitflags-1.0.1/README.md @@ -0,0 +1,29 @@ +bitflags +======== + +A Rust macro to generate structures which behave like a set of bitflags + +[![Build Status](https://travis-ci.org/rust-lang-nursery/bitflags.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/bitflags) + +- [Documentation](https://docs.rs/bitflags) +- [Release notes](https://github.com/rust-lang-nursery/bitflags/releases) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +bitflags = "1.0" +``` + +and this to your crate root: + +```rust +#[macro_use] +extern crate bitflags; +``` + +## Rust Version Support + +The minimum supported Rust version is 1.20 due to use of associated constants. diff --git a/bitflags-1.0.1/src/example_generated.rs b/bitflags-1.0.1/src/example_generated.rs new file mode 100644 index 000000000..e00310b8c --- /dev/null +++ b/bitflags-1.0.1/src/example_generated.rs @@ -0,0 +1,14 @@ +//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS +//! CRATE**. + +bitflags! { + /// This is the same `Flags` struct defined in the [crate level example](../index.html#example). + /// Note that this struct is just for documentation purposes only, it must not be used outside + /// this crate. + pub struct Flags: u32 { + const FLAG_A = 0b00000001; + const FLAG_B = 0b00000010; + const FLAG_C = 0b00000100; + const FLAG_ABC = Self::FLAG_A.bits | Self::FLAG_B.bits | Self::FLAG_C.bits; + } +} diff --git a/bitflags-1.0.1/src/lib.rs b/bitflags-1.0.1/src/lib.rs new file mode 100644 index 000000000..f5bca98e1 --- /dev/null +++ b/bitflags-1.0.1/src/lib.rs @@ -0,0 +1,1160 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A typesafe bitmask flag generator useful for sets of C-style bitmask flags. +//! It can be used for creating typesafe wrappers around C APIs. +//! +//! The `bitflags!` macro generates a `struct` that manages a set of flags. The +//! flags should only be defined for integer types, otherwise unexpected type +//! errors may occur at compile time. +//! +//! # Example +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +//! } +//! } +//! +//! fn main() { +//! let e1 = Flags::A | Flags::C; +//! let e2 = Flags::B | Flags::C; +//! assert_eq!((e1 | e2), Flags::ABC); // union +//! assert_eq!((e1 & e2), Flags::C); // intersection +//! assert_eq!((e1 - e2), Flags::A); // set difference +//! assert_eq!(!e2, Flags::A); // set complement +//! } +//! ``` +//! +//! See [`example_generated::Flags`](./example_generated/struct.Flags.html) for documentation of code +//! generated by the above `bitflags!` expansion. +//! +//! The generated `struct`s can also be extended with type and trait +//! implementations: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! use std::fmt; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! } +//! } +//! +//! impl Flags { +//! pub fn clear(&mut self) { +//! self.bits = 0; // The `bits` field can be accessed from within the +//! // same module where the `bitflags!` macro was invoked. +//! } +//! } +//! +//! impl fmt::Display for Flags { +//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +//! write!(f, "hi!") +//! } +//! } +//! +//! fn main() { +//! let mut flags = Flags::A | Flags::B; +//! flags.clear(); +//! assert!(flags.is_empty()); +//! assert_eq!(format!("{}", flags), "hi!"); +//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +//! assert_eq!(format!("{:?}", Flags::B), "B"); +//! } +//! ``` +//! +//! # Visibility +//! +//! The generated struct and its associated flag constants are not exported +//! out of the current module by default. A definition can be exported out of +//! the current module by adding `pub` before `flags`: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! mod example { +//! bitflags! { +//! pub struct Flags1: u32 { +//! const A = 0b00000001; +//! } +//! } +//! bitflags! { +//! # pub +//! struct Flags2: u32 { +//! const B = 0b00000010; +//! } +//! } +//! } +//! +//! fn main() { +//! let flag1 = example::Flags1::A; +//! let flag2 = example::Flags2::B; // error: const `B` is private +//! } +//! ``` +//! +//! # Attributes +//! +//! Attributes can be attached to the generated `struct` by placing them +//! before the `flags` keyword. +//! +//! # Trait implementations +//! +//! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash` +//! traits automatically derived for the `struct` using the `derive` attribute. +//! Additional traits can be derived by providing an explicit `derive` +//! attribute on `flags`. +//! +//! The `Extend` and `FromIterator` traits are implemented for the `struct`, +//! too: `Extend` adds the union of the instances of the `struct` iterated over, +//! while `FromIterator` calculates the union. +//! +//! The `Binary`, `Debug`, `LowerExp`, `Octal` and `UpperExp` trait is also +//! implemented by displaying the bits value of the internal struct. +//! +//! ## Operators +//! +//! The following operator traits are implemented for the generated `struct`: +//! +//! - `BitOr` and `BitOrAssign`: union +//! - `BitAnd` and `BitAndAssign`: intersection +//! - `BitXor` and `BitXorAssign`: toggle +//! - `Sub` and `SubAssign`: set difference +//! - `Not`: set complement +//! +//! # Methods +//! +//! The following methods are defined for the generated `struct`: +//! +//! - `empty`: an empty set of flags +//! - `all`: the set of all flags +//! - `bits`: the raw value of the flags currently stored +//! - `from_bits`: convert from underlying bit representation, unless that +//! representation contains bits that do not correspond to a flag +//! - `from_bits_truncate`: convert from underlying bit representation, dropping +//! any bits that do not correspond to flags +//! - `is_empty`: `true` if no flags are currently stored +//! - `is_all`: `true` if all flags are currently set +//! - `intersects`: `true` if there are flags common to both `self` and `other` +//! - `contains`: `true` all of the flags in `other` are contained within `self` +//! - `insert`: inserts the specified flags in-place +//! - `remove`: removes the specified flags in-place +//! - `toggle`: the specified flags will be inserted if not present, and removed +//! if they are. +//! - `set`: inserts or removes the specified flags depending on the passed value +//! +//! ## Default +//! +//! The `Default` trait is not automatically implemented for the generated struct. +//! +//! If your default value is equal to `0` (which is the same value as calling `empty()` +//! on the generated struct), you can simply derive `Default`: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! // Results in default value with bits: 0 +//! #[derive(Default)] +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! +//! fn main() { +//! let derived_default: Flags = Default::default(); +//! assert_eq!(derived_default.bits(), 0); +//! } +//! ``` +//! +//! If your default value is not equal to `0` you need to implement `Default` yourself: +//! +//! ``` +//! #[macro_use] +//! extern crate bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! +//! // explicit `Default` implementation +//! impl Default for Flags { +//! fn default() -> Flags { +//! Flags::A | Flags::C +//! } +//! } +//! +//! fn main() { +//! let implemented_default: Flags = Default::default(); +//! assert_eq!(implemented_default, (Flags::A | Flags::C)); +//! } +//! ``` + +#![no_std] + +#![doc(html_root_url = "https://docs.rs/bitflags/1.0.1")] + +#[cfg(test)] +#[macro_use] +extern crate std; + +// Re-export libcore using an alias so that the macros can work without +// requiring `extern crate core` downstream. +#[doc(hidden)] +pub extern crate core as _core; + +/// The macro used to generate the flag structure. +/// +/// See the [crate level docs](../bitflags/index.html) for complete documentation. +/// +/// # Example +/// +/// ``` +/// #[macro_use] +/// extern crate bitflags; +/// +/// bitflags! { +/// struct Flags: u32 { +/// const A = 0b00000001; +/// const B = 0b00000010; +/// const C = 0b00000100; +/// const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +/// } +/// } +/// +/// fn main() { +/// let e1 = Flags::A | Flags::C; +/// let e2 = Flags::B | Flags::C; +/// assert_eq!((e1 | e2), Flags::ABC); // union +/// assert_eq!((e1 & e2), Flags::C); // intersection +/// assert_eq!((e1 - e2), Flags::A); // set difference +/// assert_eq!(!e2, Flags::A); // set complement +/// } +/// ``` +/// +/// The generated `struct`s can also be extended with type and trait +/// implementations: +/// +/// ``` +/// #[macro_use] +/// extern crate bitflags; +/// +/// use std::fmt; +/// +/// bitflags! { +/// struct Flags: u32 { +/// const A = 0b00000001; +/// const B = 0b00000010; +/// } +/// } +/// +/// impl Flags { +/// pub fn clear(&mut self) { +/// self.bits = 0; // The `bits` field can be accessed from within the +/// // same module where the `bitflags!` macro was invoked. +/// } +/// } +/// +/// impl fmt::Display for Flags { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "hi!") +/// } +/// } +/// +/// fn main() { +/// let mut flags = Flags::A | Flags::B; +/// flags.clear(); +/// assert!(flags.is_empty()); +/// assert_eq!(format!("{}", flags), "hi!"); +/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +/// assert_eq!(format!("{:?}", Flags::B), "B"); +/// } +/// ``` +#[macro_export] +macro_rules! bitflags { + ( + $(#[$outer:meta])* + pub struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + __bitflags! { + $(#[$outer])* + (pub) $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; + ( + $(#[$outer:meta])* + struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + __bitflags! { + $(#[$outer])* + () $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; + ( + $(#[$outer:meta])* + pub ($($vis:tt)+) struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )+ + } + ) => { + __bitflags! { + $(#[$outer])* + (pub ($($vis)+)) $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! __bitflags { + ( + $(#[$outer:meta])* + ($($vis:tt)*) $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + $Flag:ident = $value:expr; + )+ + } + ) => { + #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] + $(#[$outer])* + $($vis)* struct $BitFlags { + bits: $T, + } + + __impl_bitflags! { + $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )+ + } + } + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! __impl_bitflags { + ( + $BitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident = $value:expr; + )+ + } + ) => { + impl $crate::_core::fmt::Debug for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + // This convoluted approach is to handle #[cfg]-based flag + // omission correctly. For example it needs to support: + // + // #[cfg(unix)] const A: Flag = /* ... */; + // #[cfg(windows)] const B: Flag = /* ... */; + + // Unconditionally define a check for every flag, even disabled + // ones. + #[allow(non_snake_case)] + trait __BitFlags { + $( + #[inline] + fn $Flag(&self) -> bool { false } + )+ + } + + // Conditionally override the check for just those flags that + // are not #[cfg]ed away. + impl __BitFlags for $BitFlags { + $( + __impl_bitflags! { + #[allow(deprecated)] + #[inline] + $(? #[$attr $($args)*])* + fn $Flag(&self) -> bool { + self.bits & Self::$Flag.bits == Self::$Flag.bits + } + } + )+ + } + + let mut first = true; + $( + if <$BitFlags as __BitFlags>::$Flag(self) { + if !first { + try!(f.write_str(" | ")); + } + first = false; + try!(f.write_str(stringify!($Flag))); + } + )+ + if first { + try!(f.write_str("(empty)")); + } + Ok(()) + } + } + impl $crate::_core::fmt::Binary for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::Binary::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::Octal for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::Octal::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::LowerHex for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::LowerHex::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::UpperHex for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::UpperHex::fmt(&self.bits, f) + } + } + + #[allow(dead_code)] + impl $BitFlags { + $( + $(#[$attr $($args)*])* + pub const $Flag: $BitFlags = $BitFlags { bits: $value }; + )+ + + /// Returns an empty set of flags. + #[inline] + pub fn empty() -> $BitFlags { + $BitFlags { bits: 0 } + } + + /// Returns the set containing all flags. + #[inline] + pub fn all() -> $BitFlags { + // See `Debug::fmt` for why this approach is taken. + #[allow(non_snake_case)] + trait __BitFlags { + $( + #[inline] + fn $Flag() -> $T { 0 } + )+ + } + impl __BitFlags for $BitFlags { + $( + __impl_bitflags! { + #[allow(deprecated)] + #[inline] + $(? #[$attr $($args)*])* + fn $Flag() -> $T { Self::$Flag.bits } + } + )+ + } + $BitFlags { bits: $(<$BitFlags as __BitFlags>::$Flag())|+ } + } + + /// Returns the raw value of the flags currently stored. + #[inline] + pub fn bits(&self) -> $T { + self.bits + } + + /// Convert from underlying bit representation, unless that + /// representation contains bits that do not correspond to a flag. + #[inline] + pub fn from_bits(bits: $T) -> $crate::_core::option::Option<$BitFlags> { + if (bits & !$BitFlags::all().bits()) == 0 { + $crate::_core::option::Option::Some($BitFlags { bits: bits }) + } else { + $crate::_core::option::Option::None + } + } + + /// Convert from underlying bit representation, dropping any bits + /// that do not correspond to flags. + #[inline] + pub fn from_bits_truncate(bits: $T) -> $BitFlags { + $BitFlags { bits: bits } & $BitFlags::all() + } + + /// Returns `true` if no flags are currently stored. + #[inline] + pub fn is_empty(&self) -> bool { + *self == $BitFlags::empty() + } + + /// Returns `true` if all flags are currently set. + #[inline] + pub fn is_all(&self) -> bool { + *self == $BitFlags::all() + } + + /// Returns `true` if there are flags common to both `self` and `other`. + #[inline] + pub fn intersects(&self, other: $BitFlags) -> bool { + !(*self & other).is_empty() + } + + /// Returns `true` all of the flags in `other` are contained within `self`. + #[inline] + pub fn contains(&self, other: $BitFlags) -> bool { + (*self & other) == other + } + + /// Inserts the specified flags in-place. + #[inline] + pub fn insert(&mut self, other: $BitFlags) { + self.bits |= other.bits; + } + + /// Removes the specified flags in-place. + #[inline] + pub fn remove(&mut self, other: $BitFlags) { + self.bits &= !other.bits; + } + + /// Toggles the specified flags in-place. + #[inline] + pub fn toggle(&mut self, other: $BitFlags) { + self.bits ^= other.bits; + } + + /// Inserts or removes the specified flags depending on the passed value. + #[inline] + pub fn set(&mut self, other: $BitFlags, value: bool) { + if value { + self.insert(other); + } else { + self.remove(other); + } + } + } + + impl $crate::_core::ops::BitOr for $BitFlags { + type Output = $BitFlags; + + /// Returns the union of the two sets of flags. + #[inline] + fn bitor(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits | other.bits } + } + } + + impl $crate::_core::ops::BitOrAssign for $BitFlags { + + /// Adds the set of flags. + #[inline] + fn bitor_assign(&mut self, other: $BitFlags) { + self.bits |= other.bits; + } + } + + impl $crate::_core::ops::BitXor for $BitFlags { + type Output = $BitFlags; + + /// Returns the left flags, but with all the right flags toggled. + #[inline] + fn bitxor(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits ^ other.bits } + } + } + + impl $crate::_core::ops::BitXorAssign for $BitFlags { + + /// Toggles the set of flags. + #[inline] + fn bitxor_assign(&mut self, other: $BitFlags) { + self.bits ^= other.bits; + } + } + + impl $crate::_core::ops::BitAnd for $BitFlags { + type Output = $BitFlags; + + /// Returns the intersection between the two sets of flags. + #[inline] + fn bitand(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & other.bits } + } + } + + impl $crate::_core::ops::BitAndAssign for $BitFlags { + + /// Disables all flags disabled in the set. + #[inline] + fn bitand_assign(&mut self, other: $BitFlags) { + self.bits &= other.bits; + } + } + + impl $crate::_core::ops::Sub for $BitFlags { + type Output = $BitFlags; + + /// Returns the set difference of the two sets of flags. + #[inline] + fn sub(self, other: $BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & !other.bits } + } + } + + impl $crate::_core::ops::SubAssign for $BitFlags { + + /// Disables all flags enabled in the set. + #[inline] + fn sub_assign(&mut self, other: $BitFlags) { + self.bits &= !other.bits; + } + } + + impl $crate::_core::ops::Not for $BitFlags { + type Output = $BitFlags; + + /// Returns the complement of this set of flags. + #[inline] + fn not(self) -> $BitFlags { + $BitFlags { bits: !self.bits } & $BitFlags::all() + } + } + + impl $crate::_core::iter::Extend<$BitFlags> for $BitFlags { + fn extend>(&mut self, iterator: T) { + for item in iterator { + self.insert(item) + } + } + } + + impl $crate::_core::iter::FromIterator<$BitFlags> for $BitFlags { + fn from_iter>(iterator: T) -> $BitFlags { + let mut result = Self::empty(); + result.extend(iterator); + result + } + } + }; + + // Every attribute that the user writes on a const is applied to the + // corresponding const that we generate, but within the implementation of + // Debug and all() we want to ignore everything but #[cfg] attributes. In + // particular, including a #[deprecated] attribute on those items would fail + // to compile. + // https://github.com/rust-lang-nursery/bitflags/issues/109 + // + // Input: + // + // ? #[cfg(feature = "advanced")] + // ? #[deprecated(note = "Use somthing else.")] + // ? #[doc = r"High quality documentation."] + // fn f() -> i32 { /* ... */ } + // + // Output: + // + // #[cfg(feature = "advanced")] + // fn f() -> i32 { /* ... */ } + ( + $(#[$filtered:meta])* + ? #[cfg $($cfgargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + fn $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + #[cfg $($cfgargs)*] + $(? #[$rest $($restargs)*])* + fn $($item)* + } + }; + ( + $(#[$filtered:meta])* + // $next != `cfg` + ? #[$next:ident $($nextargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + fn $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + // $next filtered out + $(? #[$rest $($restargs)*])* + fn $($item)* + } + }; + ( + $(#[$filtered:meta])* + fn $($item:tt)* + ) => { + $(#[$filtered])* + fn $($item)* + }; +} + +#[cfg(feature = "example_generated")] +pub mod example_generated; + +#[cfg(test)] +mod tests { + use std::hash::{Hash, Hasher}; + use std::collections::hash_map::DefaultHasher; + + bitflags! { + #[doc = "> The first principle is that you must not fool yourself — and"] + #[doc = "> you are the easiest person to fool."] + #[doc = "> "] + #[doc = "> - Richard Feynman"] + struct Flags: u32 { + const A = 0b00000001; + #[doc = " macros are way better at generating code than trans is"] + const B = 0b00000010; + const C = 0b00000100; + #[doc = "* cmr bed"] + #[doc = "* strcat table"] + #[doc = " wait what?"] + const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + } + } + + bitflags! { + struct _CfgFlags: u32 { + #[cfg(windows)] + const _CFG_A = 0b01; + #[cfg(unix)] + const _CFG_B = 0b01; + #[cfg(windows)] + const _CFG_C = _CFG_A.bits | 0b10; + } + } + + bitflags! { + struct AnotherSetOfFlags: i8 { + const ANOTHER_FLAG = -1_i8; + } + } + + bitflags! { + struct LongFlags: u32 { + const LONG_A = 0b1111111111111111; + } + } + + #[test] + fn test_bits(){ + assert_eq!(Flags::empty().bits(), 0b00000000); + assert_eq!(Flags::A.bits(), 0b00000001); + assert_eq!(Flags::ABC.bits(), 0b00000111); + + assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00); + assert_eq!(AnotherSetOfFlags::ANOTHER_FLAG.bits(), !0_i8); + } + + #[test] + fn test_from_bits() { + assert_eq!(Flags::from_bits(0), Some(Flags::empty())); + assert_eq!(Flags::from_bits(0b1), Some(Flags::A)); + assert_eq!(Flags::from_bits(0b10), Some(Flags::B)); + assert_eq!(Flags::from_bits(0b11), Some(Flags::A | Flags::B)); + assert_eq!(Flags::from_bits(0b1000), None); + + assert_eq!(AnotherSetOfFlags::from_bits(!0_i8), Some(AnotherSetOfFlags::ANOTHER_FLAG)); + } + + #[test] + fn test_from_bits_truncate() { + assert_eq!(Flags::from_bits_truncate(0), Flags::empty()); + assert_eq!(Flags::from_bits_truncate(0b1), Flags::A); + assert_eq!(Flags::from_bits_truncate(0b10), Flags::B); + assert_eq!(Flags::from_bits_truncate(0b11), (Flags::A | Flags::B)); + assert_eq!(Flags::from_bits_truncate(0b1000), Flags::empty()); + assert_eq!(Flags::from_bits_truncate(0b1001), Flags::A); + + assert_eq!(AnotherSetOfFlags::from_bits_truncate(0_i8), AnotherSetOfFlags::empty()); + } + + #[test] + fn test_is_empty(){ + assert!(Flags::empty().is_empty()); + assert!(!Flags::A.is_empty()); + assert!(!Flags::ABC.is_empty()); + + assert!(!AnotherSetOfFlags::ANOTHER_FLAG.is_empty()); + } + + #[test] + fn test_is_all() { + assert!(Flags::all().is_all()); + assert!(!Flags::A.is_all()); + assert!(Flags::ABC.is_all()); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.is_all()); + } + + #[test] + fn test_two_empties_do_not_intersect() { + let e1 = Flags::empty(); + let e2 = Flags::empty(); + assert!(!e1.intersects(e2)); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.intersects(AnotherSetOfFlags::ANOTHER_FLAG)); + } + + #[test] + fn test_empty_does_not_intersect_with_full() { + let e1 = Flags::empty(); + let e2 = Flags::ABC; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_disjoint_intersects() { + let e1 = Flags::A; + let e2 = Flags::B; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_overlapping_intersects() { + let e1 = Flags::A; + let e2 = Flags::A | Flags::B; + assert!(e1.intersects(e2)); + } + + #[test] + fn test_contains() { + let e1 = Flags::A; + let e2 = Flags::A | Flags::B; + assert!(!e1.contains(e2)); + assert!(e2.contains(e1)); + assert!(Flags::ABC.contains(e2)); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.contains(AnotherSetOfFlags::ANOTHER_FLAG)); + } + + #[test] + fn test_insert(){ + let mut e1 = Flags::A; + let e2 = Flags::A | Flags::B; + e1.insert(e2); + assert_eq!(e1, e2); + + let mut e3 = AnotherSetOfFlags::empty(); + e3.insert(AnotherSetOfFlags::ANOTHER_FLAG); + assert_eq!(e3, AnotherSetOfFlags::ANOTHER_FLAG); + } + + #[test] + fn test_remove(){ + let mut e1 = Flags::A | Flags::B; + let e2 = Flags::A | Flags::C; + e1.remove(e2); + assert_eq!(e1, Flags::B); + + let mut e3 = AnotherSetOfFlags::ANOTHER_FLAG; + e3.remove(AnotherSetOfFlags::ANOTHER_FLAG); + assert_eq!(e3, AnotherSetOfFlags::empty()); + } + + #[test] + fn test_operators() { + let e1 = Flags::A | Flags::C; + let e2 = Flags::B | Flags::C; + assert_eq!((e1 | e2), Flags::ABC); // union + assert_eq!((e1 & e2), Flags::C); // intersection + assert_eq!((e1 - e2), Flags::A); // set difference + assert_eq!(!e2, Flags::A); // set complement + assert_eq!(e1 ^ e2, Flags::A | Flags::B); // toggle + let mut e3 = e1; + e3.toggle(e2); + assert_eq!(e3, Flags::A | Flags::B); + + let mut m4 = AnotherSetOfFlags::empty(); + m4.toggle(AnotherSetOfFlags::empty()); + assert_eq!(m4, AnotherSetOfFlags::empty()); + } + + #[test] + fn test_set() { + let mut e1 = Flags::A | Flags::C; + e1.set(Flags::B, true); + e1.set(Flags::C, false); + + assert_eq!(e1, Flags::A | Flags::B); + } + + #[test] + fn test_assignment_operators() { + let mut m1 = Flags::empty(); + let e1 = Flags::A | Flags::C; + // union + m1 |= Flags::A; + assert_eq!(m1, Flags::A); + // intersection + m1 &= e1; + assert_eq!(m1, Flags::A); + // set difference + m1 -= m1; + assert_eq!(m1, Flags::empty()); + // toggle + m1 ^= e1; + assert_eq!(m1, e1); + } + + #[test] + fn test_extend() { + let mut flags; + + flags = Flags::empty(); + flags.extend([].iter().cloned()); + assert_eq!(flags, Flags::empty()); + + flags = Flags::empty(); + flags.extend([Flags::A, Flags::B].iter().cloned()); + assert_eq!(flags, Flags::A | Flags::B); + + flags = Flags::A; + flags.extend([Flags::A, Flags::B].iter().cloned()); + assert_eq!(flags, Flags::A | Flags::B); + + flags = Flags::B; + flags.extend([Flags::A, Flags::ABC].iter().cloned()); + assert_eq!(flags, Flags::ABC); + } + + #[test] + fn test_from_iterator() { + assert_eq!([].iter().cloned().collect::(), Flags::empty()); + assert_eq!([Flags::A, Flags::B].iter().cloned().collect::(), + Flags::A | Flags::B); + assert_eq!([Flags::A, Flags::ABC].iter().cloned().collect::(), + Flags::ABC); + } + + #[test] + fn test_lt() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(!(a < b) && !(b < a)); + b = Flags::B; + assert!(a < b); + a = Flags::C; + assert!(!(a < b) && b < a); + b = Flags::C | Flags::B; + assert!(a < b); + } + + #[test] + fn test_ord() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(a <= b && a >= b); + a = Flags::A; + assert!(a > b && a >= b); + assert!(b < a && b <= a); + b = Flags::B; + assert!(b > a && b >= a); + assert!(a < b && a <= b); + } + + fn hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + #[test] + fn test_hash() { + let mut x = Flags::empty(); + let mut y = Flags::empty(); + assert_eq!(hash(&x), hash(&y)); + x = Flags::all(); + y = Flags::ABC; + assert_eq!(hash(&x), hash(&y)); + } + + #[test] + fn test_debug() { + assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); + assert_eq!(format!("{:?}", Flags::empty()), "(empty)"); + assert_eq!(format!("{:?}", Flags::ABC), "A | B | C | ABC"); + } + + #[test] + fn test_binary() { + assert_eq!(format!("{:b}", Flags::ABC), "111"); + assert_eq!(format!("{:#b}", Flags::ABC), "0b111"); + } + + #[test] + fn test_octal() { + assert_eq!(format!("{:o}", LongFlags::LONG_A), "177777"); + assert_eq!(format!("{:#o}", LongFlags::LONG_A), "0o177777"); + } + + #[test] + fn test_lowerhex() { + assert_eq!(format!("{:x}", LongFlags::LONG_A), "ffff"); + assert_eq!(format!("{:#x}", LongFlags::LONG_A), "0xffff"); + } + + #[test] + fn test_upperhex() { + assert_eq!(format!("{:X}", LongFlags::LONG_A), "FFFF"); + assert_eq!(format!("{:#X}", LongFlags::LONG_A), "0xFFFF"); + } + + mod submodule { + bitflags! { + pub struct PublicFlags: i8 { + const X = 0; + } + } + bitflags! { + struct PrivateFlags: i8 { + const Y = 0; + } + } + + #[test] + fn test_private() { + + let _ = PrivateFlags::Y; + } + } + + #[test] + fn test_public() { + let _ = submodule::PublicFlags::X; + } + + mod t1 { + mod foo { + pub type Bar = i32; + } + + bitflags! { + /// baz + struct Flags: foo::Bar { + const A = 0b00000001; + #[cfg(foo)] + const B = 0b00000010; + #[cfg(foo)] + const C = 0b00000010; + } + } + } + + #[test] + fn test_in_function() { + bitflags! { + struct Flags: u8 { + const A = 1; + #[cfg(any())] // false + const B = 2; + } + } + assert_eq!(Flags::all(), Flags::A); + assert_eq!(format!("{:?}", Flags::A), "A"); + } + + #[test] + fn test_deprecated() { + bitflags! { + pub struct TestFlags: u32 { + #[deprecated(note = "Use something else.")] + const ONE = 1; + } + } + } + + #[test] + fn test_pub_crate() { + mod module { + bitflags! { + pub (crate) struct Test: u8 { + const FOO = 1; + } + } + } + + assert_eq!(module::Test::FOO.bits(), 1); + } + + #[test] + fn test_pub_in_module() { + mod module { + mod submodule { + bitflags! { + // `pub (in super)` means only the module `module` will + // be able to access this. + pub (in super) struct Test: u8 { + const FOO = 1; + } + } + } + + mod test { + // Note: due to `pub (in super)`, + // this cannot be accessed directly by the testing code. + pub (in super) fn value() -> u8 { + super::submodule::Test::FOO.bits() + } + } + + pub fn value() -> u8 { + test::value() + } + } + + assert_eq!(module::value(), 1) + } +} diff --git a/bufstream-0.1.3/.cargo-checksum.json b/bufstream-0.1.3/.cargo-checksum.json new file mode 100644 index 000000000..589110f7b --- /dev/null +++ b/bufstream-0.1.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"} \ No newline at end of file diff --git a/bufstream-0.1.3/.travis.yml b/bufstream-0.1.3/.travis.yml new file mode 100644 index 000000000..6b44b2a4c --- /dev/null +++ b/bufstream-0.1.3/.travis.yml @@ -0,0 +1,24 @@ +language: rust +rust: + - stable + - beta + - nightly +sudo: false +before_script: + - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH +script: + - cargo build --verbose + - cargo test --verbose + - cargo test --verbose --features tokio + - cargo doc --no-deps +after_success: + - travis-cargo --only nightly doc-upload +env: + global: + secure: "G857gdm63OJ2wcwdEBBeY+53D/zRSSmPfAp/H+8vRy5nnB+4GBq5Xqugq9n4BrvJMoPLMMMAmB46Chk7HHkkk/e4WTQ2orX61c4nNF3b4rdik6fzwVKk4Gy06FlM63cEa9/1iN2BiOg6NA81cmrUrK1ezIdg+8YECsiVu9+7m2g=" + + + +notifications: + email: + on_success: never diff --git a/bufstream-0.1.3/Cargo.toml b/bufstream-0.1.3/Cargo.toml new file mode 100644 index 000000000..a2d4fa4d3 --- /dev/null +++ b/bufstream-0.1.3/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "bufstream" +version = "0.1.3" +authors = ["The Rust Project Developers"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/bufstream" +homepage = "https://github.com/alexcrichton/bufstream" +documentation = "http://alexcrichton.com/bufstream" +description = """ +Buffered I/O for streams where each read/write half is separately buffered +""" + +[dependencies.futures] +optional = true +version = "0.1.13" + +[dependencies.tokio-io] +optional = true +version = "0.1.1" + +[features] +default = [] +tokio = ["futures", "tokio-io"] diff --git a/bufstream-0.1.3/LICENSE-APACHE b/bufstream-0.1.3/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/bufstream-0.1.3/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/bufstream-0.1.3/LICENSE-MIT b/bufstream-0.1.3/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/bufstream-0.1.3/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/bufstream-0.1.3/README.md b/bufstream-0.1.3/README.md new file mode 100644 index 000000000..fee754144 --- /dev/null +++ b/bufstream-0.1.3/README.md @@ -0,0 +1,22 @@ +bufstream +========= + +Buffered I/O streams for reading/writing + +[![Build Status](https://travis-ci.org/alexcrichton/bufstream.svg?branch=master)](https://travis-ci.org/alexcrichton/bufstream) + +[Documentation](http://alexcrichton.com/bufstream) + +## Usage + +```toml +[dependencies] +bufstream = "0.1" +``` + +## Tokio + +There is support for tokio's `AsyncRead` + `AsyncWrite` traits through the `tokio` +feature. When using this crate with asynchronous IO, make sure to properly flush +the stream before dropping it since IO during drop may cause panics. For the same +reason you should stay away from `BufStream::into_inner`. diff --git a/bufstream-0.1.3/src/lib.rs b/bufstream-0.1.3/src/lib.rs new file mode 100644 index 000000000..8e2e6c516 --- /dev/null +++ b/bufstream-0.1.3/src/lib.rs @@ -0,0 +1,262 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A crate for separately buffered streams. +//! +//! This crate provides a `BufStream` type which provides buffering of both the +//! reading and writing halves of a `Read + Write` type. Each half is completely +//! independently buffered of the other, which may not always be desired. For +//! example `BufStream` may have surprising semantics. +//! +//! # Usage +//! +//! ```toml +//! [dependencies] +//! bufstream = "0.1" +//! ``` +//! +//! ```no_run +//! use std::io::prelude::*; +//! use std::net::TcpStream; +//! use bufstream::BufStream; +//! +//! +//! let stream = TcpStream::connect("localhost:4000").unwrap(); +//! let mut buf = BufStream::new(stream); +//! buf.read(&mut [0; 1024]).unwrap(); +//! buf.write(&[0; 1024]).unwrap(); +//! ``` +//! +//! # Async I/O +//! +//! This crate optionally can support async I/O streams with the [Tokio stack] via +//! the `tokio` feature of this crate: +//! +//! [Tokio stack]: https://tokio.rs/ +//! +//! ```toml +//! bufstream = { version = "0.2", features = ["tokio"] } +//! ``` +//! +//! All methods are internally capable of working with streams that may return +//! [`ErrorKind::WouldBlock`] when they're not ready to perform the particular +//! operation. +//! +//! [`ErrorKind::WouldBlock`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html +//! +//! Note that care needs to be taken when using these objects, however. The +//! Tokio runtime, in particular, requires that data is fully flushed before +//! dropping streams. For compatibility with blocking streams all streams are +//! flushed/written when they are dropped, and this is not always a suitable +//! time to perform I/O. If I/O streams are flushed before drop, however, then +//! these operations will be a noop. + +#[cfg(feature = "tokio")] extern crate futures; +#[cfg(feature = "tokio")] #[macro_use] extern crate tokio_io; + +use std::fmt; +use std::io::prelude::*; +use std::io::{self, BufReader, BufWriter}; +use std::error; + +#[cfg(feature = "tokio")] use futures::Poll; +#[cfg(feature = "tokio")] use tokio_io::{AsyncRead, AsyncWrite}; + +const DEFAULT_BUF_SIZE: usize = 8 * 1024; + +/// Wraps a Stream and buffers input and output to and from it. +/// +/// It can be excessively inefficient to work directly with a `Read+Write`. For +/// example, every call to `read` or `write` on `TcpStream` results in a system +/// call. A `BufStream` keeps in memory buffers of data, making large, +/// infrequent calls to `read` and `write` on the underlying `Read+Write`. +/// +/// The output buffer will be written out when this stream is dropped. +#[derive(Debug)] +pub struct BufStream { + inner: BufReader> +} + +/// An error returned by `into_inner` which combines an error that +/// happened while writing out the buffer, and the buffered writer object +/// which may be used to recover from the condition. +#[derive(Debug)] +pub struct IntoInnerError(W, io::Error); + +impl IntoInnerError { + /// Returns the error which caused the call to `into_inner()` to fail. + /// + /// This error was returned when attempting to write the internal buffer. + pub fn error(&self) -> &io::Error { &self.1 } + /// Returns the buffered writer instance which generated the error. + /// + /// The returned object can be used for error recovery, such as + /// re-inspecting the buffer. + pub fn into_inner(self) -> W { self.0 } +} + +impl From> for io::Error { + fn from(iie: IntoInnerError) -> io::Error { iie.1 } +} + +impl error::Error for IntoInnerError { + fn description(&self) -> &str { + error::Error::description(self.error()) + } +} + +impl fmt::Display for IntoInnerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.error().fmt(f) + } +} + +struct InternalBufWriter(Option>); + +impl InternalBufWriter { + fn get_ref(&self) -> &BufWriter { + self.0.as_ref().unwrap() + } + + fn get_mut(&mut self) -> &mut BufWriter { + self.0.as_mut().unwrap() + } +} + +impl Read for InternalBufWriter { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.get_mut().get_mut().read(buf) + } +} + +impl fmt::Debug for InternalBufWriter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.get_ref().fmt(f) + } +} + +impl BufStream { + /// Creates a new buffered stream with explicitly listed capacities for the + /// reader/writer buffer. + pub fn with_capacities(reader_cap: usize, writer_cap: usize, inner: S) + -> BufStream { + let writer = BufWriter::with_capacity(writer_cap, inner); + let internal_writer = InternalBufWriter(Some(writer)); + let reader = BufReader::with_capacity(reader_cap, internal_writer); + BufStream { inner: reader } + } + + /// Creates a new buffered stream with the default reader/writer buffer + /// capacities. + pub fn new(inner: S) -> BufStream { + BufStream::with_capacities(DEFAULT_BUF_SIZE, DEFAULT_BUF_SIZE, inner) + } + + /// Gets a reference to the underlying stream. + pub fn get_ref(&self) -> &S { + self.inner.get_ref().get_ref().get_ref() + } + + /// Gets a mutable reference to the underlying stream. + /// + /// # Warning + /// + /// It is inadvisable to read directly from or write directly to the + /// underlying stream. + pub fn get_mut(&mut self) -> &mut S { + self.inner.get_mut().get_mut().get_mut() + } + + /// Unwraps this `BufStream`, returning the underlying stream. + /// + /// The internal write buffer is written out before returning the stream. + /// Any leftover data in the read buffer is lost. + pub fn into_inner(mut self) -> Result>> { + let e = { + let InternalBufWriter(ref mut w) = *self.inner.get_mut(); + let (e, w2) = match w.take().unwrap().into_inner() { + Ok(s) => return Ok(s), + Err(err) => { + (io::Error::new(err.error().kind(), err.error().to_string()), + err.into_inner()) + } + }; + *w = Some(w2); + e + }; + Err(IntoInnerError(self, e)) + } +} + +impl BufRead for BufStream { + fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() } + fn consume(&mut self, amt: usize) { self.inner.consume(amt) } + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { + self.inner.read_until(byte, buf) + } + fn read_line(&mut self, string: &mut String) -> io::Result { + self.inner.read_line(string) + } +} + +impl Read for BufStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } +} + +impl Write for BufStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.get_mut().0.as_mut().unwrap().write(buf) + } + fn flush(&mut self) -> io::Result<()> { + self.inner.get_mut().0.as_mut().unwrap().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for BufStream {} + +#[cfg(feature = "tokio")] +impl AsyncWrite for BufStream { + fn shutdown(&mut self) -> Poll<(), io::Error> { + try_nb!(self.flush()); + let mut inner = self.inner.get_mut().0.as_mut().unwrap(); + inner.shutdown() + } +} + +#[cfg(test)] +mod tests { + use std::io::prelude::*; + use std::io; + + use super::BufStream; + // This is just here to make sure that we don't infinite loop in the + // newtype struct autoderef weirdness + #[test] + fn test_buffered_stream() { + struct S; + + impl Write for S { + fn write(&mut self, b: &[u8]) -> io::Result { Ok(b.len()) } + fn flush(&mut self) -> io::Result<()> { Ok(()) } + } + + impl Read for S { + fn read(&mut self, _: &mut [u8]) -> io::Result { Ok(0) } + } + + let mut stream = BufStream::new(S); + assert_eq!(stream.read(&mut [0; 10]).unwrap(), 0); + stream.write(&[0; 10]).unwrap(); + stream.flush().unwrap(); + } +} diff --git a/cc-1.0.4/.cargo-checksum.json b/cc-1.0.4/.cargo-checksum.json new file mode 100644 index 000000000..db43eefac --- /dev/null +++ b/cc-1.0.4/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"deaf9ec656256bb25b404c51ef50097207b9cbb29c933d31f92cae5a8a0ffee0"} \ No newline at end of file diff --git a/cc-1.0.4/.travis.yml b/cc-1.0.4/.travis.yml new file mode 100644 index 000000000..6f3c53d9a --- /dev/null +++ b/cc-1.0.4/.travis.yml @@ -0,0 +1,53 @@ +language: rust +sudo: false + +matrix: + include: + - rust: 1.13.0 + install: + script: cargo build + - rust: stable + env: TARGET=x86_64-unknown-linux-gnu NO_ADD=1 + - rust: stable + env: TARGET=i686-unknown-linux-gnu + - os: osx + env: TARGET=x86_64-apple-darwin NO_ADD=1 + - rust: beta + env: TARGET=x86_64-unknown-linux-gnu NO_ADD=1 + - rust: nightly + env: TARGET=x86_64-unknown-linux-gnu NO_ADD=1 + + - rust: nightly + before_script: + - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH + install: + script: + - cargo doc --no-deps --all-features + after_success: + - travis-cargo --only nightly doc-upload + +install: + - if [ -z "$NO_ADD" ]; then rustup target add $TARGET; fi + +script: + - cargo build --verbose + - cargo test --verbose + - cargo test --verbose --features parallel + - cargo test --manifest-path cc-test/Cargo.toml --target $TARGET + - cargo test --manifest-path cc-test/Cargo.toml --target $TARGET --features parallel + - cargo test --manifest-path cc-test/Cargo.toml --target $TARGET --release + - cargo doc + - cargo clean && cargo build + - rustdoc --test README.md -L target/debug -L target/debug/deps + +env: + global: + secure: "CBtqrudgE0PS8x3kTr44jKbC2D4nfnmdYVecooNm0qnER4B4TSvZpZSQoCgKK6k4BYQuOSyFTOwYx6M79w39ZMOgyCP9ytB+tyMWL0/+ZuUQL04yVg4M5vd3oJMkOaXbvG56ncgPyFrseY+FPDg+mXAzvJk/nily37YXjkQj2D0=" + +notifications: + email: + on_success: never +addons: + apt: + packages: + - g++-multilib diff --git a/cc-1.0.4/Cargo.toml b/cc-1.0.4/Cargo.toml new file mode 100644 index 000000000..44560a614 --- /dev/null +++ b/cc-1.0.4/Cargo.toml @@ -0,0 +1,37 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "cc" +version = "1.0.4" +authors = ["Alex Crichton "] +description = "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n" +homepage = "https://github.com/alexcrichton/cc-rs" +documentation = "https://docs.rs/cc" +readme = "README.md" +keywords = ["build-dependencies"] +categories = ["development-tools"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/cc-rs" +[dependencies.rayon] +version = "0.9" +optional = true +[dev-dependencies.tempdir] +version = "0.3" + +[features] +parallel = ["rayon"] +[badges.appveyor] +repository = "alexcrichton/cc-rs" + +[badges.travis-ci] +repository = "alexcrichton/cc-rs" diff --git a/cc-1.0.4/LICENSE-APACHE b/cc-1.0.4/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/cc-1.0.4/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/cc-1.0.4/LICENSE-MIT b/cc-1.0.4/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/cc-1.0.4/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/cc-1.0.4/README.md b/cc-1.0.4/README.md new file mode 100644 index 000000000..94efa4310 --- /dev/null +++ b/cc-1.0.4/README.md @@ -0,0 +1,202 @@ +# cc-rs + +A library to compile C/C++/assembly into a Rust library/application. + +[![Build Status](https://travis-ci.org/alexcrichton/cc-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/cc-rs) +[![Build status](https://ci.appveyor.com/api/projects/status/onu270iw98h81nwv?svg=true)](https://ci.appveyor.com/project/alexcrichton/cc-rs) + +[Documentation](https://docs.rs/cc) + +A simple library meant to be used as a build dependency with Cargo packages in +order to build a set of C/C++ files into a static archive. This crate calls out +to the most relevant compiler for a platform, for example using `cl` on MSVC. + +> **Note**: this crate was recently renamed from the `gcc` crate, so if you're +> looking for the `gcc` crate you're in the right spot! + +## Using cc-rs + +First, you'll want to both add a build script for your crate (`build.rs`) and +also add this crate to your `Cargo.toml` via: + +```toml +[build-dependencies] +cc = "1.0" +``` + +Next up, you'll want to write a build script like so: + +```rust,no_run +// build.rs + +extern crate cc; + +fn main() { + cc::Build::new() + .file("foo.c") + .file("bar.c") + .compile("foo"); +} +``` + +And that's it! Running `cargo build` should take care of the rest and your Rust +application will now have the C files `foo.c` and `bar.c` compiled into a file +named libfoo.a. You can call the functions in Rust by declaring functions in +your Rust code like so: + +``` +extern { + fn foo_function(); + fn bar_function(); +} + +pub fn call() { + unsafe { + foo_function(); + bar_function(); + } +} + +fn main() { + // ... +} +``` + +## External configuration via environment variables + +To control the programs and flags used for building, the builder can set a +number of different environment variables. + +* `CFLAGS` - a series of space separated flags passed to compilers. Note that + individual flags cannot currently contain spaces, so doing + something like: "-L=foo\ bar" is not possible. +* `CC` - the actual C compiler used. Note that this is used as an exact + executable name, so (for example) no extra flags can be passed inside + this variable, and the builder must ensure that there aren't any + trailing spaces. This compiler must understand the `-c` flag. For + certain `TARGET`s, it also is assumed to know about other flags (most + common is `-fPIC`). +* `AR` - the `ar` (archiver) executable to use to build the static library. + +Each of these variables can also be supplied with certain prefixes and suffixes, +in the following prioritized order: + +1. `_` - for example, `CC_x86_64-unknown-linux-gnu` +2. `_` - for example, `CC_x86_64_unknown_linux_gnu` +3. `_` - for example, `HOST_CC` or `TARGET_CFLAGS` +4. `` - a plain `CC`, `AR` as above. + +If none of these variables exist, cc-rs uses built-in defaults + +In addition to the the above optional environment variables, `cc-rs` has some +functions with hard requirements on some variables supplied by [cargo's +build-script driver][cargo] that it has the `TARGET`, `OUT_DIR`, `OPT_LEVEL`, +and `HOST` variables. + +[cargo]: http://doc.crates.io/build-script.html#inputs-to-the-build-script + +## Optional features + +### Parallel + +Currently cc-rs supports parallel compilation (think `make -jN`) but this +feature is turned off by default. To enable cc-rs to compile C/C++ in parallel, +you can change your dependency to: + +```toml +[build-dependencies] +cc = { version = "1.0", features = ["parallel"] } +``` + +By default cc-rs will limit parallelism to `$NUM_JOBS`, or if not present it +will limit it to the number of cpus on the machine. If you are using cargo, +use `-jN` option of `build`, `test` and `run` commands as `$NUM_JOBS` +is supplied by cargo. + +## Compile-time Requirements + +To work properly this crate needs access to a C compiler when the build script +is being run. This crate does not ship a C compiler with it. The compiler +required varies per platform, but there are three broad categories: + +* Unix platforms require `cc` to be the C compiler. This can be found by + installing cc/clang on Linux distributions and Xcode on OSX, for example. +* Windows platforms targeting MSVC (e.g. your target triple ends in `-msvc`) + require `cl.exe` to be available and in `PATH`. This is typically found in + standard Visual Studio installations and the `PATH` can be set up by running + the appropriate developer tools shell. +* Windows platforms targeting MinGW (e.g. your target triple ends in `-gnu`) + require `cc` to be available in `PATH`. We recommend the + [MinGW-w64](http://mingw-w64.org) distribution, which is using the + [Win-builds](http://win-builds.org) installation system. + You may also acquire it via + [MSYS2](http://msys2.github.io), as explained [here][msys2-help]. Make sure + to install the appropriate architecture corresponding to your installation of + rustc. GCC from older [MinGW](http://www.mingw.org) project is compatible + only with 32-bit rust compiler. + +[msys2-help]: http://github.com/rust-lang/rust#building-on-windows + +## C++ support + +`cc-rs` supports C++ libraries compilation by using the `cpp` method on +`Build`: + +```rust,no_run +extern crate cc; + +fn main() { + cc::Build::new() + .cpp(true) // Switch to C++ library compilation. + .file("foo.cpp") + .compile("libfoo.a"); +} +``` + +When using C++ library compilation switch, the `CXX` and `CXXFLAGS` env +variables are used instead of `CC` and `CFLAGS` and the C++ standard library is +linked to the crate target. + +## CUDA C++ support + +`cc-rs` also supports compiling CUDA C++ libraries by using the `cuda` method +on `Build` (currently for GNU/Clang toolchains only): + +```rust,no_run +extern crate cc; + +fn main() { + cc::Build::new() + // Switch to CUDA C++ library compilation using NVCC. + .cuda(true) + // Generate code for Maxwell (GTX 970, 980, 980 Ti, Titan X). + .flag("-gencode").flag("arch=compute_52,code=sm_52") + // Generate code for Maxwell (Jetson TX1). + .flag("-gencode").flag("arch=compute_53,code=sm_53") + // Generate code for Pascal (GTX 1070, 1080, 1080 Ti, Titan Xp). + .flag("-gencode").flag("arch=compute_61,code=sm_61") + // Generate code for Pascal (Tesla P100). + .flag("-gencode").flag("arch=compute_60,code=sm_60") + // Generate code for Pascal (Jetson TX2). + .flag("-gencode").flag("arch=compute_62,code=sm_62") + .file("bar.cu") + .compile("libbar.a"); +} +``` + +## License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/cc-1.0.4/appveyor.yml b/cc-1.0.4/appveyor.yml new file mode 100644 index 000000000..5e563db1c --- /dev/null +++ b/cc-1.0.4/appveyor.yml @@ -0,0 +1,55 @@ +environment: + + # At the time this was added AppVeyor was having troubles with checking + # revocation of SSL certificates of sites like static.rust-lang.org and what + # we think is crates.io. The libcurl HTTP client by default checks for + # revocation on Windows and according to a mailing list [1] this can be + # disabled. + # + # The `CARGO_HTTP_CHECK_REVOKE` env var here tells cargo to disable SSL + # revocation checking on Windows in libcurl. Note, though, that rustup, which + # we're using to download Rust here, also uses libcurl as the default backend. + # Unlike Cargo, however, rustup doesn't have a mechanism to disable revocation + # checking. To get rustup working we set `RUSTUP_USE_HYPER` which forces it to + # use the Hyper instead of libcurl backend. Both Hyper and libcurl use + # schannel on Windows but it appears that Hyper configures it slightly + # differently such that revocation checking isn't turned on by default. + # + # [1]: https://curl.haxx.se/mail/lib-2016-03/0202.html + RUSTUP_USE_HYPER: 1 + CARGO_HTTP_CHECK_REVOKE: false + + matrix: + - TARGET: x86_64-pc-windows-msvc + ARCH: amd64 + VS: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat + - TARGET: x86_64-pc-windows-msvc + ARCH: amd64 + VS: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat + - TARGET: i686-pc-windows-msvc + ARCH: x86 + VS: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat + - TARGET: i686-pc-windows-msvc + ARCH: x86 + VS: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat + - TARGET: x86_64-pc-windows-gnu + MSYS_BITS: 64 + - TARGET: i686-pc-windows-gnu + MSYS_BITS: 32 +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - if defined VS call "%VS%" %ARCH% + - set PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - if defined MSYS_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS_BITS%\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --target %TARGET% + - cargo test --features parallel --target %TARGET% + - cargo test --manifest-path cc-test/Cargo.toml --target %TARGET% + - cargo test --manifest-path cc-test/Cargo.toml --features parallel --target %TARGET% + - cargo test --manifest-path cc-test/Cargo.toml --release --target %TARGET% diff --git a/cc-1.0.4/src/bin/gcc-shim.rs b/cc-1.0.4/src/bin/gcc-shim.rs new file mode 100644 index 000000000..7fd0ea8fa --- /dev/null +++ b/cc-1.0.4/src/bin/gcc-shim.rs @@ -0,0 +1,23 @@ +#![cfg_attr(test, allow(dead_code))] + +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::path::PathBuf; + +fn main() { + let out_dir = PathBuf::from(env::var_os("GCCTEST_OUT_DIR").unwrap()); + for i in 0.. { + let candidate = out_dir.join(format!("out{}", i)); + if candidate.exists() { + continue; + } + let mut f = File::create(candidate).unwrap(); + for arg in env::args().skip(1) { + writeln!(f, "{}", arg).unwrap(); + } + + File::create(out_dir.join("libfoo.a")).unwrap(); + break; + } +} diff --git a/cc-1.0.4/src/com.rs b/cc-1.0.4/src/com.rs new file mode 100644 index 000000000..bd8cce714 --- /dev/null +++ b/cc-1.0.4/src/com.rs @@ -0,0 +1,125 @@ +// Copyright © 2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused)] + +use std::ffi::{OsStr, OsString}; +use std::mem::forget; +use std::ops::Deref; +use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::ptr::null_mut; +use std::slice::from_raw_parts; +use winapi::Interface; +use winapi::BSTR; +use winapi::CoInitializeEx; +use winapi::COINIT_MULTITHREADED; +use winapi::{SysFreeString, SysStringLen}; +use winapi::IUnknown; +use winapi::{S_OK, S_FALSE, HRESULT}; + +pub fn initialize() -> Result<(), HRESULT> { + let err = unsafe { CoInitializeEx(null_mut(), COINIT_MULTITHREADED) }; + if err != S_OK && err != S_FALSE { + // S_FALSE just means COM is already initialized + return Err(err); + } + Ok(()) +} + +pub struct ComPtr(*mut T) where T: Interface; +impl ComPtr where T: Interface { + /// Creates a `ComPtr` to wrap a raw pointer. + /// It takes ownership over the pointer which means it does __not__ call `AddRef`. + /// `T` __must__ be a COM interface that inherits from `IUnknown`. + pub unsafe fn from_raw(ptr: *mut T) -> ComPtr { + assert!(!ptr.is_null()); + ComPtr(ptr) + } + /// Casts up the inheritance chain + pub fn up(self) -> ComPtr where T: Deref, U: Interface { + ComPtr(self.into_raw() as *mut U) + } + /// Extracts the raw pointer. + /// You are now responsible for releasing it yourself. + pub fn into_raw(self) -> *mut T { + let p = self.0; + forget(self); + p + } + /// For internal use only. + fn as_unknown(&self) -> &IUnknown { + unsafe { &*(self.0 as *mut IUnknown) } + } + /// Performs QueryInterface fun. + pub fn cast(&self) -> Result, i32> where U: Interface { + let mut obj = null_mut(); + let err = unsafe { self.as_unknown().QueryInterface(&U::uuidof(), &mut obj) }; + if err < 0 { return Err(err); } + Ok(unsafe { ComPtr::from_raw(obj as *mut U) }) + } +} +impl Deref for ComPtr where T: Interface { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.0 } + } +} +impl Clone for ComPtr where T: Interface { + fn clone(&self) -> Self { + unsafe { + self.as_unknown().AddRef(); + ComPtr::from_raw(self.0) + } + } +} +impl Drop for ComPtr where T: Interface { + fn drop(&mut self) { + unsafe { self.as_unknown().Release(); } + } +} +pub struct BStr(BSTR); +impl BStr { + pub unsafe fn from_raw(s: BSTR) -> BStr { + BStr(s) + } + pub fn to_osstring(&self) -> OsString { + let len = unsafe { SysStringLen(self.0) }; + let slice = unsafe { from_raw_parts(self.0, len as usize) }; + OsStringExt::from_wide(slice) + } +} +impl Drop for BStr { + fn drop(&mut self) { + unsafe { SysFreeString(self.0) }; + } +} + +pub trait ToWide { + fn to_wide(&self) -> Vec; + fn to_wide_null(&self) -> Vec; +} +impl ToWide for T where T: AsRef { + fn to_wide(&self) -> Vec { + self.as_ref().encode_wide().collect() + } + fn to_wide_null(&self) -> Vec { + self.as_ref().encode_wide().chain(Some(0)).collect() + } +} +pub trait FromWide where Self: Sized { + fn from_wide(wide: &[u16]) -> Self; + fn from_wide_null(wide: &[u16]) -> Self { + let len = wide.iter().take_while(|&&c| c != 0).count(); + Self::from_wide(&wide[..len]) + } +} +impl FromWide for OsString { + fn from_wide(wide: &[u16]) -> OsString { + OsStringExt::from_wide(wide) + } +} + diff --git a/cc-1.0.4/src/lib.rs b/cc-1.0.4/src/lib.rs new file mode 100644 index 000000000..67d8f6fce --- /dev/null +++ b/cc-1.0.4/src/lib.rs @@ -0,0 +1,1998 @@ +//! A library for build scripts to compile custom C code +//! +//! This library is intended to be used as a `build-dependencies` entry in +//! `Cargo.toml`: +//! +//! ```toml +//! [build-dependencies] +//! cc = "1.0" +//! ``` +//! +//! The purpose of this crate is to provide the utility functions necessary to +//! compile C code into a static archive which is then linked into a Rust crate. +//! Configuration is available through the `Build` struct. +//! +//! This crate will automatically detect situations such as cross compilation or +//! other environment variables set by Cargo and will build code appropriately. +//! +//! The crate is not limited to C code, it can accept any source code that can +//! be passed to a C or C++ compiler. As such, assembly files with extensions +//! `.s` (gcc/clang) and `.asm` (MSVC) can also be compiled. +//! +//! [`Build`]: struct.Build.html +//! +//! # Parallelism +//! +//! To parallelize computation, enable the `parallel` feature for the crate. +//! +//! ```toml +//! [build-dependencies] +//! cc = { version = "1.0", features = ["parallel"] } +//! ``` +//! To specify the max number of concurrent compilation jobs, set the `NUM_JOBS` +//! environment variable to the desired amount. +//! +//! Cargo will also set this environment variable when executed with the `-jN` flag. +//! +//! If `NUM_JOBS` is not set, the `RAYON_NUM_THREADS` environment variable can +//! also specify the build paralellism. +//! +//! # Examples +//! +//! Use the `Build` struct to compile `src/foo.c`: +//! +//! ```no_run +//! extern crate cc; +//! +//! fn main() { +//! cc::Build::new() +//! .file("src/foo.c") +//! .define("FOO", Some("bar")) +//! .include("src") +//! .compile("foo"); +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/cc/1.0")] +#![cfg_attr(test, deny(warnings))] +#![deny(missing_docs)] + +#[cfg(feature = "parallel")] +extern crate rayon; + +use std::env; +use std::ffi::{OsString, OsStr}; +use std::fs; +use std::path::{PathBuf, Path}; +use std::process::{Command, Stdio, Child}; +use std::io::{self, BufReader, BufRead, Read, Write}; +use std::thread::{self, JoinHandle}; + +#[cfg(feature = "parallel")] +use std::sync::Mutex; + +// These modules are all glue to support reading the MSVC version from +// the registry and from COM interfaces +#[cfg(windows)] +mod registry; +#[cfg(windows)] +#[macro_use] +mod winapi; +#[cfg(windows)] +mod com; +#[cfg(windows)] +mod setup_config; + +pub mod windows_registry; + +/// A builder for compilation of a native static library. +/// +/// A `Build` is the main type of the `cc` crate and is used to control all the +/// various configuration options and such of a compile. You'll find more +/// documentation on each method itself. +#[derive(Clone, Debug)] +pub struct Build { + include_directories: Vec, + definitions: Vec<(String, Option)>, + objects: Vec, + flags: Vec, + flags_supported: Vec, + files: Vec, + cpp: bool, + cpp_link_stdlib: Option>, + cpp_set_stdlib: Option, + cuda: bool, + target: Option, + host: Option, + out_dir: Option, + opt_level: Option, + debug: Option, + env: Vec<(OsString, OsString)>, + compiler: Option, + archiver: Option, + cargo_metadata: bool, + pic: Option, + static_crt: Option, + shared_flag: Option, + static_flag: Option, + warnings_into_errors: bool, + warnings: bool, +} + +/// Represents the types of errors that may occur while using cc-rs. +#[derive(Clone, Debug)] +enum ErrorKind { + /// Error occurred while performing I/O. + IOError, + /// Invalid architecture supplied. + ArchitectureInvalid, + /// Environment variable not found, with the var in question as extra info. + EnvVarNotFound, + /// Error occurred while using external tools (ie: invocation of compiler). + ToolExecError, + /// Error occurred due to missing external tools. + ToolNotFound, +} + +/// Represents an internal error that occurred, with an explanation. +#[derive(Clone, Debug)] +pub struct Error { + /// Describes the kind of error that occurred. + kind: ErrorKind, + /// More explanation of error that occurred. + message: String, +} + +impl Error { + fn new(kind: ErrorKind, message: &str) -> Error { + Error { + kind: kind, + message: message.to_owned(), + } + } +} + +impl From for Error { + fn from(e: io::Error) -> Error { + Error::new(ErrorKind::IOError, &format!("{}", e)) + } +} + +/// Configuration used to represent an invocation of a C compiler. +/// +/// This can be used to figure out what compiler is in use, what the arguments +/// to it are, and what the environment variables look like for the compiler. +/// This can be used to further configure other build systems (e.g. forward +/// along CC and/or CFLAGS) or the `to_command` method can be used to run the +/// compiler itself. +#[derive(Clone, Debug)] +pub struct Tool { + path: PathBuf, + cc_wrapper_path: Option, + cc_wrapper_args: Vec, + args: Vec, + env: Vec<(OsString, OsString)>, + family: ToolFamily, + cuda: bool, +} + +/// Represents the family of tools this tool belongs to. +/// +/// Each family of tools differs in how and what arguments they accept. +/// +/// Detection of a family is done on best-effort basis and may not accurately reflect the tool. +#[derive(Copy, Clone, Debug, PartialEq)] +enum ToolFamily { + /// Tool is GNU Compiler Collection-like. + Gnu, + /// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags + /// and its cross-compilation approach is different. + Clang, + /// Tool is the MSVC cl.exe. + Msvc, +} + +impl ToolFamily { + /// What the flag to request debug info for this family of tools look like + fn debug_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc => "/Z7", + ToolFamily::Gnu | ToolFamily::Clang => "-g", + } + } + + /// What the flag to include directories into header search path looks like + fn include_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc => "/I", + ToolFamily::Gnu | ToolFamily::Clang => "-I", + } + } + + /// What the flag to request macro-expanded source output looks like + fn expand_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc => "/E", + ToolFamily::Gnu | ToolFamily::Clang => "-E", + } + } + + /// What the flags to enable all warnings + fn warnings_flags(&self) -> &'static [&'static str] { + static MSVC_FLAGS: &'static [&'static str] = &["/W4"]; + static GNU_CLANG_FLAGS: &'static [&'static str] = &["-Wall", "-Wextra"]; + + match *self { + ToolFamily::Msvc => &MSVC_FLAGS, + ToolFamily::Gnu | ToolFamily::Clang => &GNU_CLANG_FLAGS, + } + } + + /// What the flag to turn warning into errors + fn warnings_to_errors_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc => "/WX", + ToolFamily::Gnu | ToolFamily::Clang => "-Werror", + } + } + + /// NVCC-specific. Device code debug info flag. This is separate from the + /// debug info flag passed to the C++ compiler. + fn nvcc_debug_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc => unimplemented!(), + ToolFamily::Gnu | + ToolFamily::Clang => "-G", + } + } + + /// NVCC-specific. Redirect the following flag to the underlying C++ + /// compiler. + fn nvcc_redirect_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc => unimplemented!(), + ToolFamily::Gnu | + ToolFamily::Clang => "-Xcompiler", + } + } +} + +/// Represents an object. +/// +/// This is a source file -> object file pair. +#[derive(Clone, Debug)] +struct Object { + src: PathBuf, + dst: PathBuf, +} + +impl Object { + /// Create a new source file -> object file pair. + fn new(src: PathBuf, dst: PathBuf) -> Object { + Object { + src: src, + dst: dst, + } + } +} + +impl Build { + /// Construct a new instance of a blank set of configuration. + /// + /// This builder is finished with the [`compile`] function. + /// + /// [`compile`]: struct.Build.html#method.compile + pub fn new() -> Build { + Build { + include_directories: Vec::new(), + definitions: Vec::new(), + objects: Vec::new(), + flags: Vec::new(), + flags_supported: Vec::new(), + files: Vec::new(), + shared_flag: None, + static_flag: None, + cpp: false, + cpp_link_stdlib: None, + cpp_set_stdlib: None, + cuda: false, + target: None, + host: None, + out_dir: None, + opt_level: None, + debug: None, + env: Vec::new(), + compiler: None, + archiver: None, + cargo_metadata: true, + pic: None, + static_crt: None, + warnings: true, + warnings_into_errors: false, + } + } + + /// Add a directory to the `-I` or include path for headers + /// + /// # Example + /// + /// ```no_run + /// use std::path::Path; + /// + /// let library_path = Path::new("/path/to/library"); + /// + /// cc::Build::new() + /// .file("src/foo.c") + /// .include(library_path) + /// .include("src") + /// .compile("foo"); + /// ``` + pub fn include>(&mut self, dir: P) -> &mut Build { + self.include_directories.push(dir.as_ref().to_path_buf()); + self + } + + /// Specify a `-D` variable with an optional value. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .define("FOO", "BAR") + /// .define("BAZ", None) + /// .compile("foo"); + /// ``` + pub fn define<'a, V: Into>>(&mut self, var: &str, val: V) -> &mut Build { + self.definitions.push(( + var.to_string(), + val.into().map(|s| s.to_string()), + )); + self + } + + /// Add an arbitrary object file to link in + pub fn object>(&mut self, obj: P) -> &mut Build { + self.objects.push(obj.as_ref().to_path_buf()); + self + } + + /// Add an arbitrary flag to the invocation of the compiler + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .flag("-ffunction-sections") + /// .compile("foo"); + /// ``` + pub fn flag(&mut self, flag: &str) -> &mut Build { + self.flags.push(flag.to_string()); + self + } + + fn ensure_check_file(&self) -> Result { + let out_dir = self.get_out_dir()?; + let src = if self.cuda { + assert!(self.cpp); + out_dir.join("flag_check.cu") + } else if self.cpp { + out_dir.join("flag_check.cpp") + } else { + out_dir.join("flag_check.c") + }; + + if !src.exists() { + let mut f = fs::File::create(&src)?; + write!(f, "int main(void) {{ return 0; }}")?; + } + + Ok(src) + } + + /// Run the compiler to test if it accepts the given flag. + /// + /// For a convenience method for setting flags conditionally, + /// see `flag_if_supported()`. + /// + /// It may return error if it's unable to run the compilier with a test file + /// (e.g. the compiler is missing or a write to the `out_dir` failed). + pub fn is_flag_supported(&self, flag: &str) -> Result { + let out_dir = self.get_out_dir()?; + let src = self.ensure_check_file()?; + let obj = out_dir.join("flag_check"); + let target = self.get_target()?; + let mut cfg = Build::new(); + cfg.flag(flag) + .target(&target) + .opt_level(0) + .host(&target) + .debug(false) + .cpp(self.cpp) + .cuda(self.cuda); + let compiler = cfg.try_get_compiler()?; + let mut cmd = compiler.to_command(); + command_add_output_file(&mut cmd, &obj, target.contains("msvc"), false); + + // We need to explicitly tell msvc not to link and create an exe + // in the root directory of the crate + if target.contains("msvc") { + cmd.arg("/c"); + } + + cmd.arg(&src); + + let output = cmd.output()?; + Ok(output.stderr.is_empty()) + } + + /// Add an arbitrary flag to the invocation of the compiler if it supports it + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .flag_if_supported("-Wlogical-op") // only supported by GCC + /// .flag_if_supported("-Wunreachable-code") // only supported by clang + /// .compile("foo"); + /// ``` + pub fn flag_if_supported(&mut self, flag: &str) -> &mut Build { + self.flags_supported.push(flag.to_string()); + self + } + + /// Set the `-shared` flag. + /// + /// When enabled, the compiler will produce a shared object which can + /// then be linked with other objects to form an executable. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .compile("libfoo.so"); + /// ``` + + pub fn shared_flag(&mut self, shared_flag: bool) -> &mut Build { + self.shared_flag = Some(shared_flag); + self + } + + /// Set the `-static` flag. + /// + /// When enabled on systems that support dynamic linking, this prevents + /// linking with the shared libraries. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .static_flag(true) + /// .compile("foo"); + /// ``` + pub fn static_flag(&mut self, static_flag: bool) -> &mut Build { + self.static_flag = Some(static_flag); + self + } + + /// Add a file which will be compiled + pub fn file>(&mut self, p: P) -> &mut Build { + self.files.push(p.as_ref().to_path_buf()); + self + } + + /// Add files which will be compiled + pub fn files

(&mut self, p: P) -> &mut Build + where + P: IntoIterator, + P::Item: AsRef, + { + for file in p.into_iter() { + self.file(file); + } + self + } + + /// Set C++ support. + /// + /// The other `cpp_*` options will only become active if this is set to + /// `true`. + pub fn cpp(&mut self, cpp: bool) -> &mut Build { + self.cpp = cpp; + self + } + + /// Set CUDA C++ support. + /// + /// Enabling CUDA will pass the detected C/C++ toolchain as an argument to + /// the CUDA compiler, NVCC. NVCC itself accepts some limited GNU-like args; + /// any other arguments for the C/C++ toolchain will be redirected using + /// "-Xcompiler" flags. + /// + /// If enabled, this also implicitly enables C++ support. + pub fn cuda(&mut self, cuda: bool) -> &mut Build { + self.cuda = cuda; + if cuda { + self.cpp = true; + } + self + } + + /// Set warnings into errors flag. + /// + /// Disabled by default. + /// + /// Warning: turning warnings into errors only make sense + /// if you are a developer of the crate using cc-rs. + /// Some warnings only appear on some architecture or + /// specific version of the compiler. Any user of this crate, + /// or any other crate depending on it, could fail during + /// compile time. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .warnings_into_errors(true) + /// .compile("libfoo.a"); + /// ``` + pub fn warnings_into_errors(&mut self, warnings_into_errors: bool) -> &mut Build { + self.warnings_into_errors = warnings_into_errors; + self + } + + /// Set warnings flags. + /// + /// Adds some flags: + /// - "/Wall" for MSVC. + /// - "-Wall", "-Wextra" for GNU and Clang. + /// + /// Enabled by default. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .warnings(false) + /// .compile("libfoo.a"); + /// ``` + pub fn warnings(&mut self, warnings: bool) -> &mut Build { + self.warnings = warnings; + self + } + + /// Set the standard library to link against when compiling with C++ + /// support. + /// + /// The default value of this property depends on the current target: On + /// OS X `Some("c++")` is used, when compiling for a Visual Studio based + /// target `None` is used and for other targets `Some("stdc++")` is used. + /// + /// A value of `None` indicates that no automatic linking should happen, + /// otherwise cargo will link against the specified library. + /// + /// The given library name must not contain the `lib` prefix. + /// + /// Common values: + /// - `stdc++` for GNU + /// - `c++` for Clang + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .cpp_link_stdlib("stdc++") + /// .compile("libfoo.so"); + /// ``` + pub fn cpp_link_stdlib<'a, V: Into>>( + &mut self, + cpp_link_stdlib: V, + ) -> &mut Build { + self.cpp_link_stdlib = Some(cpp_link_stdlib.into().map(|s| s.into())); + self + } + + /// Force the C++ compiler to use the specified standard library. + /// + /// Setting this option will automatically set `cpp_link_stdlib` to the same + /// value. + /// + /// The default value of this option is always `None`. + /// + /// This option has no effect when compiling for a Visual Studio based + /// target. + /// + /// This option sets the `-stdlib` flag, which is only supported by some + /// compilers (clang, icc) but not by others (gcc). The library will not + /// detect which compiler is used, as such it is the responsibility of the + /// caller to ensure that this option is only used in conjuction with a + /// compiler which supports the `-stdlib` flag. + /// + /// A value of `None` indicates that no specific C++ standard library should + /// be used, otherwise `-stdlib` is added to the compile invocation. + /// + /// The given library name must not contain the `lib` prefix. + /// + /// Common values: + /// - `stdc++` for GNU + /// - `c++` for Clang + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .cpp_set_stdlib("c++") + /// .compile("libfoo.a"); + /// ``` + pub fn cpp_set_stdlib<'a, V: Into>>( + &mut self, + cpp_set_stdlib: V, + ) -> &mut Build { + let cpp_set_stdlib = cpp_set_stdlib.into(); + self.cpp_set_stdlib = cpp_set_stdlib.map(|s| s.into()); + self.cpp_link_stdlib(cpp_set_stdlib); + self + } + + /// Configures the target this configuration will be compiling for. + /// + /// This option is automatically scraped from the `TARGET` environment + /// variable by build scripts, so it's not required to call this function. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .target("aarch64-linux-android") + /// .compile("foo"); + /// ``` + pub fn target(&mut self, target: &str) -> &mut Build { + self.target = Some(target.to_string()); + self + } + + /// Configures the host assumed by this configuration. + /// + /// This option is automatically scraped from the `HOST` environment + /// variable by build scripts, so it's not required to call this function. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .host("arm-linux-gnueabihf") + /// .compile("foo"); + /// ``` + pub fn host(&mut self, host: &str) -> &mut Build { + self.host = Some(host.to_string()); + self + } + + /// Configures the optimization level of the generated object files. + /// + /// This option is automatically scraped from the `OPT_LEVEL` environment + /// variable by build scripts, so it's not required to call this function. + pub fn opt_level(&mut self, opt_level: u32) -> &mut Build { + self.opt_level = Some(opt_level.to_string()); + self + } + + /// Configures the optimization level of the generated object files. + /// + /// This option is automatically scraped from the `OPT_LEVEL` environment + /// variable by build scripts, so it's not required to call this function. + pub fn opt_level_str(&mut self, opt_level: &str) -> &mut Build { + self.opt_level = Some(opt_level.to_string()); + self + } + + /// Configures whether the compiler will emit debug information when + /// generating object files. + /// + /// This option is automatically scraped from the `PROFILE` environment + /// variable by build scripts (only enabled when the profile is "debug"), so + /// it's not required to call this function. + pub fn debug(&mut self, debug: bool) -> &mut Build { + self.debug = Some(debug); + self + } + + /// Configures the output directory where all object files and static + /// libraries will be located. + /// + /// This option is automatically scraped from the `OUT_DIR` environment + /// variable by build scripts, so it's not required to call this function. + pub fn out_dir>(&mut self, out_dir: P) -> &mut Build { + self.out_dir = Some(out_dir.as_ref().to_owned()); + self + } + + /// Configures the compiler to be used to produce output. + /// + /// This option is automatically determined from the target platform or a + /// number of environment variables, so it's not required to call this + /// function. + pub fn compiler>(&mut self, compiler: P) -> &mut Build { + self.compiler = Some(compiler.as_ref().to_owned()); + self + } + + /// Configures the tool used to assemble archives. + /// + /// This option is automatically determined from the target platform or a + /// number of environment variables, so it's not required to call this + /// function. + pub fn archiver>(&mut self, archiver: P) -> &mut Build { + self.archiver = Some(archiver.as_ref().to_owned()); + self + } + /// Define whether metadata should be emitted for cargo allowing it to + /// automatically link the binary. Defaults to `true`. + /// + /// The emitted metadata is: + /// + /// - `rustc-link-lib=static=`*compiled lib* + /// - `rustc-link-search=native=`*target folder* + /// - When target is MSVC, the ATL-MFC libs are added via `rustc-link-search=native=` + /// - When C++ is enabled, the C++ stdlib is added via `rustc-link-lib` + /// + pub fn cargo_metadata(&mut self, cargo_metadata: bool) -> &mut Build { + self.cargo_metadata = cargo_metadata; + self + } + + /// Configures whether the compiler will emit position independent code. + /// + /// This option defaults to `false` for `windows-gnu` targets and + /// to `true` for all other targets. + pub fn pic(&mut self, pic: bool) -> &mut Build { + self.pic = Some(pic); + self + } + + /// Configures whether the /MT flag or the /MD flag will be passed to msvc build tools. + /// + /// This option defaults to `false`, and affect only msvc targets. + pub fn static_crt(&mut self, static_crt: bool) -> &mut Build { + self.static_crt = Some(static_crt); + self + } + + #[doc(hidden)] + pub fn __set_env(&mut self, a: A, b: B) -> &mut Build + where + A: AsRef, + B: AsRef, + { + self.env.push( + (a.as_ref().to_owned(), b.as_ref().to_owned()), + ); + self + } + + /// Run the compiler, generating the file `output` + /// + /// This will return a result instead of panicing; see compile() for the complete description. + pub fn try_compile(&self, output: &str) -> Result<(), Error> { + let (lib_name, gnu_lib_name) = if output.starts_with("lib") && output.ends_with(".a") { + (&output[3..output.len() - 2], output.to_owned()) + } else { + let mut gnu = String::with_capacity(5 + output.len()); + gnu.push_str("lib"); + gnu.push_str(&output); + gnu.push_str(".a"); + (output, gnu) + }; + let dst = self.get_out_dir()?; + + let mut objects = Vec::new(); + for file in self.files.iter() { + let obj = dst.join(file).with_extension("o"); + let obj = if !obj.starts_with(&dst) { + dst.join(obj.file_name().ok_or_else(|| { + Error::new(ErrorKind::IOError, "Getting object file details failed.") + })?) + } else { + obj + }; + + match obj.parent() { + Some(s) => fs::create_dir_all(s)?, + None => { + return Err(Error::new( + ErrorKind::IOError, + "Getting object file details failed.", + )) + } + }; + + objects.push(Object::new(file.to_path_buf(), obj)); + } + self.compile_objects(&objects)?; + self.assemble(lib_name, &dst.join(gnu_lib_name), &objects)?; + + if self.get_target()?.contains("msvc") { + let compiler = self.get_base_compiler()?; + let atlmfc_lib = compiler + .env() + .iter() + .find(|&&(ref var, _)| var.as_os_str() == OsStr::new("LIB")) + .and_then(|&(_, ref lib_paths)| { + env::split_paths(lib_paths).find(|path| { + let sub = Path::new("atlmfc/lib"); + path.ends_with(sub) || path.parent().map_or(false, |p| p.ends_with(sub)) + }) + }); + + if let Some(atlmfc_lib) = atlmfc_lib { + self.print(&format!( + "cargo:rustc-link-search=native={}", + atlmfc_lib.display() + )); + } + } + + self.print(&format!("cargo:rustc-link-lib=static={}", lib_name)); + self.print(&format!("cargo:rustc-link-search=native={}", dst.display())); + + // Add specific C++ libraries, if enabled. + if self.cpp { + if let Some(stdlib) = self.get_cpp_link_stdlib()? { + self.print(&format!("cargo:rustc-link-lib={}", stdlib)); + } + } + + Ok(()) + } + + /// Run the compiler, generating the file `output` + /// + /// The name `output` should be the name of the library. For backwards compatibility, + /// the `output` may start with `lib` and end with `.a`. The Rust compilier will create + /// the assembly with the lib prefix and .a extension. MSVC will create a file without prefix, + /// ending with `.lib`. + /// + /// # Panics + /// + /// Panics if `output` is not formatted correctly or if one of the underlying + /// compiler commands fails. It can also panic if it fails reading file names + /// or creating directories. + pub fn compile(&self, output: &str) { + if let Err(e) = self.try_compile(output) { + fail(&e.message); + } + } + + #[cfg(feature = "parallel")] + fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> { + use self::rayon::prelude::*; + + let mut cfg = rayon::Configuration::new(); + if let Ok(amt) = env::var("NUM_JOBS") { + if let Ok(amt) = amt.parse() { + cfg = cfg.num_threads(amt); + } + } + drop(rayon::initialize(cfg)); + + let results: Mutex>> = Mutex::new(Vec::new()); + + objs.par_iter().with_max_len(1).for_each( + |obj| { + let res = self.compile_object(obj); + results.lock().unwrap().push(res) + }, + ); + + // Check for any errors and return the first one found. + for result in results.into_inner().unwrap().iter() { + if result.is_err() { + return result.clone(); + } + } + + Ok(()) + } + + #[cfg(not(feature = "parallel"))] + fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> { + for obj in objs { + self.compile_object(obj)?; + } + Ok(()) + } + + fn compile_object(&self, obj: &Object) -> Result<(), Error> { + let is_asm = obj.src.extension().and_then(|s| s.to_str()) == Some("asm"); + let msvc = self.get_target()?.contains("msvc"); + let (mut cmd, name) = if msvc && is_asm { + self.msvc_macro_assembler()? + } else { + let compiler = self.try_get_compiler()?; + let mut cmd = compiler.to_command(); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + ( + cmd, + compiler + .path + .file_name() + .ok_or_else(|| { + Error::new(ErrorKind::IOError, "Failed to get compiler path.") + })? + .to_string_lossy() + .into_owned(), + ) + }; + command_add_output_file(&mut cmd, &obj.dst, msvc, is_asm); + cmd.arg(if msvc { "/c" } else { "-c" }); + cmd.arg(&obj.src); + + run(&mut cmd, &name)?; + Ok(()) + } + + /// This will return a result instead of panicing; see expand() for the complete description. + pub fn try_expand(&self) -> Result, Error> { + let compiler = self.try_get_compiler()?; + let mut cmd = compiler.to_command(); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + cmd.arg(compiler.family.expand_flag()); + + assert!( + self.files.len() <= 1, + "Expand may only be called for a single file" + ); + + for file in self.files.iter() { + cmd.arg(file); + } + + let name = compiler + .path + .file_name() + .ok_or_else(|| { + Error::new(ErrorKind::IOError, "Failed to get compiler path.") + })? + .to_string_lossy() + .into_owned(); + + Ok(run_output(&mut cmd, &name)?) + } + + /// Run the compiler, returning the macro-expanded version of the input files. + /// + /// This is only relevant for C and C++ files. + /// + /// # Panics + /// Panics if more than one file is present in the config, or if compiler + /// path has an invalid file name. + /// + /// # Example + /// ```no_run + /// let out = cc::Build::new().file("src/foo.c").expand(); + /// ``` + pub fn expand(&self) -> Vec { + match self.try_expand() { + Err(e) => fail(&e.message), + Ok(v) => v, + } + } + + /// Get the compiler that's in use for this configuration. + /// + /// This function will return a `Tool` which represents the culmination + /// of this configuration at a snapshot in time. The returned compiler can + /// be inspected (e.g. the path, arguments, environment) to forward along to + /// other tools, or the `to_command` method can be used to invoke the + /// compiler itself. + /// + /// This method will take into account all configuration such as debug + /// information, optimization level, include directories, defines, etc. + /// Additionally, the compiler binary in use follows the standard + /// conventions for this path, e.g. looking at the explicitly set compiler, + /// environment variables (a number of which are inspected here), and then + /// falling back to the default configuration. + /// + /// # Panics + /// + /// Panics if an error occurred while determining the architecture. + pub fn get_compiler(&self) -> Tool { + match self.try_get_compiler() { + Ok(tool) => tool, + Err(e) => fail(&e.message), + } + } + + /// Get the compiler that's in use for this configuration. + /// + /// This will return a result instead of panicing; see get_compiler() for the complete description. + pub fn try_get_compiler(&self) -> Result { + let opt_level = self.get_opt_level()?; + let target = self.get_target()?; + + let mut cmd = self.get_base_compiler()?; + + // Non-target flags + // If the flag is not conditioned on target variable, it belongs here :) + match cmd.family { + ToolFamily::Msvc => { + assert!(!self.cuda, + "CUDA C++ compilation not supported for MSVC, yet... but you are welcome to implement it :)"); + + cmd.args.push("/nologo".into()); + + let crt_flag = match self.static_crt { + Some(true) => "/MT", + Some(false) => "/MD", + None => { + let features = + env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or(String::new()); + if features.contains("crt-static") { + "/MT" + } else { + "/MD" + } + } + }; + cmd.args.push(crt_flag.into()); + + match &opt_level[..] { + "z" | "s" => cmd.args.push("/Os".into()), + "1" => cmd.args.push("/O1".into()), + // -O3 is a valid value for gcc and clang compilers, but not msvc. Cap to /O2. + "2" | "3" => cmd.args.push("/O2".into()), + _ => {} + } + } + ToolFamily::Gnu | ToolFamily::Clang => { + // arm-linux-androideabi-gcc 4.8 shipped with Android NDK does + // not support '-Oz' + if opt_level == "z" && cmd.family != ToolFamily::Clang { + cmd.args.push("-Os".into()); + } else { + cmd.args.push(format!("-O{}", opt_level).into()); + } + + cmd.push_cc_arg("-ffunction-sections".into()); + cmd.push_cc_arg("-fdata-sections".into()); + if self.pic.unwrap_or(!target.contains("windows-gnu")) { + cmd.push_cc_arg("-fPIC".into()); + } + } + } + for arg in self.envflags(if self.cpp { "CXXFLAGS" } else { "CFLAGS" }) { + cmd.args.push(arg.into()); + } + + if self.get_debug() { + if self.cuda { + let nvcc_debug_flag = cmd.family.nvcc_debug_flag().into(); + cmd.args.push(nvcc_debug_flag); + } + let debug_flag = cmd.family.debug_flag().into(); + cmd.push_cc_arg(debug_flag); + } + + // Target flags + match cmd.family { + ToolFamily::Clang => { + cmd.args.push(format!("--target={}", target).into()); + } + ToolFamily::Msvc => { + if target.contains("i586") { + cmd.args.push("/ARCH:IA32".into()); + } + } + ToolFamily::Gnu => { + if target.contains("i686") || target.contains("i586") { + cmd.args.push("-m32".into()); + } else if target == "x86_64-unknown-linux-gnux32" { + cmd.args.push("-mx32".into()); + } else if target.contains("x86_64") || target.contains("powerpc64") { + cmd.args.push("-m64".into()); + } + + if self.static_flag.is_none() && target.contains("musl") { + cmd.args.push("-static".into()); + } + + // armv7 targets get to use armv7 instructions + if target.starts_with("armv7-") && target.contains("-linux-") { + cmd.args.push("-march=armv7-a".into()); + } + + // On android we can guarantee some extra float instructions + // (specified in the android spec online) + if target.starts_with("armv7-linux-androideabi") { + cmd.args.push("-march=armv7-a".into()); + cmd.args.push("-mthumb".into()); + cmd.args.push("-mfpu=vfpv3-d16".into()); + cmd.args.push("-mfloat-abi=softfp".into()); + } + + if target.starts_with("armv4t-unknown-linux-") { + cmd.args.push("-march=armv4t".into()); + cmd.args.push("-marm".into()); + cmd.args.push("-mfloat-abi=soft".into()); + } + + if target.starts_with("armv5te-unknown-linux-") { + cmd.args.push("-march=armv5te".into()); + cmd.args.push("-marm".into()); + cmd.args.push("-mfloat-abi=soft".into()); + } + + // For us arm == armv6 by default + if target.starts_with("arm-unknown-linux-") { + cmd.args.push("-march=armv6".into()); + cmd.args.push("-marm".into()); + } + + // We can guarantee some settings for FRC + if target.starts_with("arm-frc-") { + cmd.args.push("-march=armv7-a".into()); + cmd.args.push("-mcpu=cortex-a9".into()); + cmd.args.push("-mfpu=vfpv3".into()); + cmd.args.push("-mfloat-abi=softfp".into()); + cmd.args.push("-marm".into()); + } + + // Turn codegen down on i586 to avoid some instructions. + if target.starts_with("i586-unknown-linux-") { + cmd.args.push("-march=pentium".into()); + } + + // Set codegen level for i686 correctly + if target.starts_with("i686-unknown-linux-") { + cmd.args.push("-march=i686".into()); + } + + // Looks like `musl-gcc` makes is hard for `-m32` to make its way + // all the way to the linker, so we need to actually instruct the + // linker that we're generating 32-bit executables as well. This'll + // typically only be used for build scripts which transitively use + // these flags that try to compile executables. + if target == "i686-unknown-linux-musl" { + cmd.args.push("-Wl,-melf_i386".into()); + } + + if target.starts_with("thumb") { + cmd.args.push("-mthumb".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfloat-abi=hard".into()) + } + } + if target.starts_with("thumbv6m") { + cmd.args.push("-march=armv6s-m".into()); + } + if target.starts_with("thumbv7em") { + cmd.args.push("-march=armv7e-m".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfpu=fpv4-sp-d16".into()) + } + } + if target.starts_with("thumbv7m") { + cmd.args.push("-march=armv7-m".into()); + } + } + } + + if target.contains("-ios") { + // FIXME: potential bug. iOS is always compiled with Clang, but Gcc compiler may be + // detected instead. + self.ios_flags(&mut cmd)?; + } + + if self.static_flag.unwrap_or(false) { + cmd.args.push("-static".into()); + } + if self.shared_flag.unwrap_or(false) { + cmd.args.push("-shared".into()); + } + + if self.cpp { + match (self.cpp_set_stdlib.as_ref(), cmd.family) { + (None, _) => {} + (Some(stdlib), ToolFamily::Gnu) | + (Some(stdlib), ToolFamily::Clang) => { + cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); + } + _ => { + println!( + "cargo:warning=cpp_set_stdlib is specified, but the {:?} compiler \ + does not support this option, ignored", + cmd.family + ); + } + } + } + + for directory in self.include_directories.iter() { + cmd.args.push(cmd.family.include_flag().into()); + cmd.args.push(directory.into()); + } + + if self.warnings { + for flag in cmd.family.warnings_flags().iter() { + cmd.push_cc_arg(flag.into()); + } + } + + for flag in self.flags.iter() { + cmd.args.push(flag.into()); + } + + for flag in self.flags_supported.iter() { + if self.is_flag_supported(flag).unwrap_or(false) { + cmd.push_cc_arg(flag.into()); + } + } + + for &(ref key, ref value) in self.definitions.iter() { + let lead = if let ToolFamily::Msvc = cmd.family { + "/" + } else { + "-" + }; + if let Some(ref value) = *value { + cmd.args.push(format!("{}D{}={}", lead, key, value).into()); + } else { + cmd.args.push(format!("{}D{}", lead, key).into()); + } + } + + if self.warnings_into_errors { + let warnings_to_errors_flag = cmd.family.warnings_to_errors_flag().into(); + cmd.push_cc_arg(warnings_to_errors_flag); + } + + Ok(cmd) + } + + fn msvc_macro_assembler(&self) -> Result<(Command, String), Error> { + let target = self.get_target()?; + let tool = if target.contains("x86_64") { + "ml64.exe" + } else { + "ml.exe" + }; + let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| self.cmd(tool)); + for directory in self.include_directories.iter() { + cmd.arg("/I").arg(directory); + } + for &(ref key, ref value) in self.definitions.iter() { + if let Some(ref value) = *value { + cmd.arg(&format!("/D{}={}", key, value)); + } else { + cmd.arg(&format!("/D{}", key)); + } + } + + if target.contains("i686") || target.contains("i586") { + cmd.arg("/safeseh"); + } + for flag in self.flags.iter() { + cmd.arg(flag); + } + + Ok((cmd, tool.to_string())) + } + + fn assemble(&self, lib_name: &str, dst: &Path, objs: &[Object]) -> Result<(), Error> { + // Delete the destination if it exists as the `ar` tool at least on Unix + // appends to it, which we don't want. + let _ = fs::remove_file(&dst); + + let objects: Vec<_> = objs.iter().map(|obj| obj.dst.clone()).collect(); + let target = self.get_target()?; + if target.contains("msvc") { + let mut cmd = match self.archiver { + Some(ref s) => self.cmd(s), + None => { + windows_registry::find(&target, "lib.exe").unwrap_or_else( + || { + self.cmd("lib.exe") + }, + ) + } + }; + let mut out = OsString::from("/OUT:"); + out.push(dst); + run( + cmd.arg(out).arg("/nologo").args(&objects).args(&self.objects), + "lib.exe", + )?; + + // The Rust compiler will look for libfoo.a and foo.lib, but the + // MSVC linker will also be passed foo.lib, so be sure that both + // exist for now. + let lib_dst = dst.with_file_name(format!("{}.lib", lib_name)); + let _ = fs::remove_file(&lib_dst); + match fs::hard_link(&dst, &lib_dst).or_else(|_| { + // if hard-link fails, just copy (ignoring the number of bytes written) + fs::copy(&dst, &lib_dst).map(|_| ()) + }) { + Ok(_) => (), + Err(_) => { + return Err(Error::new( + ErrorKind::IOError, + "Could not copy or create a hard-link to the generated lib file.", + )) + } + }; + } else { + let (mut ar, cmd) = self.get_ar()?; + run( + ar.arg("crs").arg(dst).args(&objects).args(&self.objects), + &cmd, + )?; + } + + Ok(()) + } + + fn ios_flags(&self, cmd: &mut Tool) -> Result<(), Error> { + enum ArchSpec { + Device(&'static str), + Simulator(&'static str), + } + + let target = self.get_target()?; + let arch = target.split('-').nth(0).ok_or_else(|| { + Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + ) + })?; + let arch = match arch { + "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"), + "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"), + "arm64" | "aarch64" => ArchSpec::Device("arm64"), + "i386" | "i686" => ArchSpec::Simulator("-m32"), + "x86_64" => ArchSpec::Simulator("-m64"), + _ => { + return Err(Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + )) + } + }; + + let sdk = match arch { + ArchSpec::Device(arch) => { + cmd.args.push("-arch".into()); + cmd.args.push(arch.into()); + cmd.args.push("-miphoneos-version-min=7.0".into()); + "iphoneos" + } + ArchSpec::Simulator(arch) => { + cmd.args.push(arch.into()); + cmd.args.push("-mios-simulator-version-min=7.0".into()); + "iphonesimulator" + } + }; + + self.print(&format!("Detecting iOS SDK path for {}", sdk)); + let sdk_path = self.cmd("xcrun") + .arg("--show-sdk-path") + .arg("--sdk") + .arg(sdk) + .stderr(Stdio::inherit()) + .output()? + .stdout; + + let sdk_path = match String::from_utf8(sdk_path) { + Ok(p) => p, + Err(_) => { + return Err(Error::new( + ErrorKind::IOError, + "Unable to determine iOS SDK path.", + )) + } + }; + + cmd.args.push("-isysroot".into()); + cmd.args.push(sdk_path.trim().into()); + + Ok(()) + } + + fn cmd>(&self, prog: P) -> Command { + let mut cmd = Command::new(prog); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + cmd + } + + fn get_base_compiler(&self) -> Result { + if let Some(ref c) = self.compiler { + return Ok(Tool::new(c.clone())); + } + let host = self.get_host()?; + let target = self.get_target()?; + let (env, msvc, gnu, traditional) = if self.cpp { + ("CXX", "cl.exe", "g++", "c++") + } else { + ("CC", "cl.exe", "gcc", "cc") + }; + + // On Solaris, c++/cc unlikely to exist or be correct. + let default = if host.contains("solaris") { gnu } else { traditional }; + + let tool_opt: Option = + self.env_tool(env) + .map(|(tool, cc, args)| { + let mut t = Tool::new(PathBuf::from(tool)); + if let Some(cc) = cc { + t.cc_wrapper_path = Some(PathBuf::from(cc)); + } + for arg in args { + t.cc_wrapper_args.push(arg.into()); + } + t + }) + .or_else(|| { + if target.contains("emscripten") { + let tool = if self.cpp { "em++" } else { "emcc" }; + // Windows uses bat file so we have to be a bit more specific + if cfg!(windows) { + let mut t = Tool::new(PathBuf::from("cmd")); + t.args.push("/c".into()); + t.args.push(format!("{}.bat", tool).into()); + Some(t) + } else { + Some(Tool::new(PathBuf::from(tool))) + } + } else { + None + } + }) + .or_else(|| windows_registry::find_tool(&target, "cl.exe")); + + let tool = match tool_opt { + Some(t) => t, + None => { + let compiler = if host.contains("windows") && target.contains("windows") { + if target.contains("msvc") { + msvc.to_string() + } else { + format!("{}.exe", gnu) + } + } else if target.contains("android") { + format!("{}-{}", target.replace("armv7", "arm"), gnu) + } else if target.contains("cloudabi") { + format!("{}-{}", target, traditional) + } else if self.get_host()? != target { + // CROSS_COMPILE is of the form: "arm-linux-gnueabi-" + let cc_env = self.getenv("CROSS_COMPILE"); + let cross_compile = cc_env.as_ref().map(|s| s.trim_right_matches('-')); + let prefix = cross_compile.or(match &target[..] { + "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"), + "aarch64-unknown-linux-musl" => Some("aarch64-linux-musl"), + "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv4t-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv5te-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "arm-frc-linux-gnueabi" => Some("arm-frc-linux-gnueabi"), + "arm-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "arm-unknown-linux-musleabi" => Some("arm-linux-musleabi"), + "arm-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "arm-unknown-netbsd-eabi" => Some("arm--netbsdelf-eabi"), + "armv6-unknown-netbsd-eabihf" => Some("armv6--netbsdelf-eabihf"), + "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "armv7-unknown-netbsd-eabihf" => Some("armv7--netbsdelf-eabihf"), + "i686-pc-windows-gnu" => Some("i686-w64-mingw32"), + "i686-unknown-linux-musl" => Some("musl"), + "i686-unknown-netbsd" => Some("i486--netbsdelf"), + "mips-unknown-linux-gnu" => Some("mips-linux-gnu"), + "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"), + "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"), + "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"), + "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc-unknown-netbsd" => Some("powerpc--netbsd"), + "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"), + "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"), + "sparc64-unknown-linux-gnu" => Some("sparc64-linux-gnu"), + "sparc64-unknown-netbsd" => Some("sparc64--netbsd"), + "sparcv9-sun-solaris" => Some("sparcv9-sun-solaris"), + "thumbv6m-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabihf" => Some("arm-none-eabi"), + "thumbv7m-none-eabi" => Some("arm-none-eabi"), + "x86_64-pc-windows-gnu" => Some("x86_64-w64-mingw32"), + "x86_64-rumprun-netbsd" => Some("x86_64-rumprun-netbsd"), + "x86_64-unknown-linux-musl" => Some("musl"), + "x86_64-unknown-netbsd" => Some("x86_64--netbsd"), + _ => None, + }); + match prefix { + Some(prefix) => format!("{}-{}", prefix, gnu), + None => default.to_string(), + } + } else { + default.to_string() + }; + Tool::new(PathBuf::from(compiler)) + } + }; + + let tool = if self.cuda { + assert!(tool.args.is_empty(), + "CUDA compilation currently assumes empty pre-existing args"); + let nvcc = match self.get_var("NVCC") { + Err(_) => "nvcc".into(), + Ok(nvcc) => nvcc, + }; + let mut nvcc_tool = Tool::with_features(PathBuf::from(nvcc), self.cuda); + nvcc_tool.args.push(format!("-ccbin={}", tool.path.display()).into()); + nvcc_tool + } else { + tool + }; + + Ok(tool) + } + + fn get_var(&self, var_base: &str) -> Result { + let target = self.get_target()?; + let host = self.get_host()?; + let kind = if host == target { "HOST" } else { "TARGET" }; + let target_u = target.replace("-", "_"); + let res = self.getenv(&format!("{}_{}", var_base, target)) + .or_else(|| self.getenv(&format!("{}_{}", var_base, target_u))) + .or_else(|| self.getenv(&format!("{}_{}", kind, var_base))) + .or_else(|| self.getenv(var_base)); + + match res { + Some(res) => Ok(res), + None => Err(Error::new( + ErrorKind::EnvVarNotFound, + &format!( + "Could not find environment variable {}.", + var_base + ), + )), + } + } + + fn envflags(&self, name: &str) -> Vec { + self.get_var(name) + .unwrap_or(String::new()) + .split(|c: char| c.is_whitespace()) + .filter(|s| !s.is_empty()) + .map(|s| s.to_string()) + .collect() + } + + + /// Returns compiler path, optional modifier name from whitelist, and arguments vec + fn env_tool(&self, name: &str) -> Option<(String, Option, Vec)> { + self.get_var(name).ok().map(|tool| { + let whitelist = ["ccache", "distcc", "sccache"]; + + for t in whitelist.iter() { + if tool.starts_with(t) && tool[t.len()..].starts_with(' ') { + let args = tool.split_whitespace().collect::>(); + + return (args[1].to_string(), Some(t.to_string()), args[2..].iter().map(|s| s.to_string()).collect()); + } + } + (tool, None, Vec::new()) + }) + } + + /// Returns the default C++ standard library for the current target: `libc++` + /// for OS X and `libstdc++` for anything else. + fn get_cpp_link_stdlib(&self) -> Result, Error> { + match self.cpp_link_stdlib.clone() { + Some(s) => Ok(s), + None => { + let target = self.get_target()?; + if target.contains("msvc") { + Ok(None) + } else if target.contains("darwin") { + Ok(Some("c++".to_string())) + } else if target.contains("freebsd") { + Ok(Some("c++".to_string())) + } else if target.contains("openbsd") { + Ok(Some("c++".to_string())) + } else { + Ok(Some("stdc++".to_string())) + } + } + } + } + + fn get_ar(&self) -> Result<(Command, String), Error> { + if let Some(ref p) = self.archiver { + let name = p.file_name().and_then(|s| s.to_str()).unwrap_or("ar"); + return Ok((self.cmd(p), name.to_string())); + } + if let Ok(p) = self.get_var("AR") { + return Ok((self.cmd(&p), p)); + } + let program = if self.get_target()?.contains("android") { + format!("{}-ar", self.get_target()?.replace("armv7", "arm")) + } else if self.get_target()?.contains("emscripten") { + // Windows use bat files so we have to be a bit more specific + if cfg!(windows) { + let mut cmd = self.cmd("cmd"); + cmd.arg("/c").arg("emar.bat"); + return Ok((cmd, "emar.bat".to_string())); + } + + "emar".to_string() + } else { + "ar".to_string() + }; + Ok((self.cmd(&program), program)) + } + + fn get_target(&self) -> Result { + match self.target.clone() { + Some(t) => Ok(t), + None => Ok(self.getenv_unwrap("TARGET")?), + } + } + + fn get_host(&self) -> Result { + match self.host.clone() { + Some(h) => Ok(h), + None => Ok(self.getenv_unwrap("HOST")?), + } + } + + fn get_opt_level(&self) -> Result { + match self.opt_level.as_ref().cloned() { + Some(ol) => Ok(ol), + None => Ok(self.getenv_unwrap("OPT_LEVEL")?), + } + } + + fn get_debug(&self) -> bool { + self.debug.unwrap_or_else(|| match self.getenv("DEBUG") { + Some(s) => s != "false", + None => false, + }) + } + + fn get_out_dir(&self) -> Result { + match self.out_dir.clone() { + Some(p) => Ok(p), + None => Ok(env::var_os("OUT_DIR").map(PathBuf::from).ok_or_else(|| { + Error::new( + ErrorKind::EnvVarNotFound, + "Environment variable OUT_DIR not defined.", + ) + })?), + } + } + + fn getenv(&self, v: &str) -> Option { + let r = env::var(v).ok(); + self.print(&format!("{} = {:?}", v, r)); + r + } + + fn getenv_unwrap(&self, v: &str) -> Result { + match self.getenv(v) { + Some(s) => Ok(s), + None => Err(Error::new( + ErrorKind::EnvVarNotFound, + &format!( + "Environment variable {} not defined.", + v.to_string() + ), + )), + } + } + + fn print(&self, s: &str) { + if self.cargo_metadata { + println!("{}", s); + } + } +} + +impl Default for Build { + fn default() -> Build { + Build::new() + } +} + +impl Tool { + fn new(path: PathBuf) -> Tool { + Tool::with_features(path, false) + } + + fn with_features(path: PathBuf, cuda: bool) -> Tool { + // Try to detect family of the tool from its name, falling back to Gnu. + let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) { + if fname.contains("clang") { + ToolFamily::Clang + } else if fname.contains("cl") && !fname.contains("cloudabi") && + !fname.contains("uclibc") { + ToolFamily::Msvc + } else { + ToolFamily::Gnu + } + } else { + ToolFamily::Gnu + }; + Tool { + path: path, + cc_wrapper_path: None, + cc_wrapper_args: Vec::new(), + args: Vec::new(), + env: Vec::new(), + family: family, + cuda: cuda, + } + } + + /// Add a flag, and optionally prepend the NVCC wrapper flag "-Xcompiler". + /// + /// Currently this is only used for compiling CUDA sources, since NVCC only + /// accepts a limited set of GNU-like flags, and the rest must be prefixed + /// with a "-Xcompiler" flag to get passed to the underlying C++ compiler. + fn push_cc_arg(&mut self, flag: OsString) { + if self.cuda { + self.args.push(self.family.nvcc_redirect_flag().into()); + } + self.args.push(flag); + } + + /// Converts this compiler into a `Command` that's ready to be run. + /// + /// This is useful for when the compiler needs to be executed and the + /// command returned will already have the initial arguments and environment + /// variables configured. + pub fn to_command(&self) -> Command { + let mut cmd = match self.cc_wrapper_path { + Some(ref cc_wrapper_path) => { + let mut cmd = Command::new(&cc_wrapper_path); + cmd.arg(&self.path); + cmd.args(&self.cc_wrapper_args); + cmd + }, + None => Command::new(&self.path) + }; + cmd.args(&self.args); + for &(ref k, ref v) in self.env.iter() { + cmd.env(k, v); + } + cmd + } + + /// Returns the path for this compiler. + /// + /// Note that this may not be a path to a file on the filesystem, e.g. "cc", + /// but rather something which will be resolved when a process is spawned. + pub fn path(&self) -> &Path { + &self.path + } + + /// Returns the default set of arguments to the compiler needed to produce + /// executables for the target this compiler generates. + pub fn args(&self) -> &[OsString] { + &self.args + } + + /// Returns the set of environment variables needed for this compiler to + /// operate. + /// + /// This is typically only used for MSVC compilers currently. + pub fn env(&self) -> &[(OsString, OsString)] { + &self.env + } + + /// Returns the compiler command in format of CC environment variable. + /// Or empty string if CC env was not present + /// + /// This is typically used by configure script + pub fn cc_env(&self) -> OsString { + match self.cc_wrapper_path { + Some(ref cc_wrapper_path) => { + let mut cc_env = cc_wrapper_path.as_os_str().to_owned(); + cc_env.push(" "); + cc_env.push(self.path.to_path_buf().into_os_string()); + for arg in self.cc_wrapper_args.iter() { + cc_env.push(" "); + cc_env.push(arg); + } + cc_env + }, + None => { + OsString::from("") + } + } + } + + /// Returns the compiler flags in format of CFLAGS environment variable. + /// Important here - this will not be CFLAGS from env, its internal gcc's flags to use as CFLAGS + /// This is typically used by configure script + pub fn cflags_env(&self) -> OsString { + let mut flags = OsString::new(); + for (i, arg) in self.args.iter().enumerate() { + if i > 0 { + flags.push(" "); + } + flags.push(arg); + } + flags + } + + /// Whether the tool is GNU Compiler Collection-like. + pub fn is_like_gnu(&self) -> bool { + self.family == ToolFamily::Gnu + } + + /// Whether the tool is Clang-like. + pub fn is_like_clang(&self) -> bool { + self.family == ToolFamily::Clang + } + + /// Whether the tool is MSVC-like. + pub fn is_like_msvc(&self) -> bool { + self.family == ToolFamily::Msvc + } +} + +fn run(cmd: &mut Command, program: &str) -> Result<(), Error> { + let (mut child, print) = spawn(cmd, program)?; + let status = match child.wait() { + Ok(s) => s, + Err(_) => { + return Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Failed to wait on spawned child process, command {:?} with args {:?}.", + cmd, + program + ), + )) + } + }; + print.join().unwrap(); + println!("{}", status); + + if status.success() { + Ok(()) + } else { + Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Command {:?} with args {:?} did not execute successfully (status code {}).", + cmd, + program, + status + ), + )) + } +} + +fn run_output(cmd: &mut Command, program: &str) -> Result, Error> { + cmd.stdout(Stdio::piped()); + let (mut child, print) = spawn(cmd, program)?; + let mut stdout = vec![]; + child + .stdout + .take() + .unwrap() + .read_to_end(&mut stdout) + .unwrap(); + let status = match child.wait() { + Ok(s) => s, + Err(_) => { + return Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Failed to wait on spawned child process, command {:?} with args {:?}.", + cmd, + program + ), + )) + } + }; + print.join().unwrap(); + println!("{}", status); + + if status.success() { + Ok(stdout) + } else { + Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Command {:?} with args {:?} did not execute successfully (status code {}).", + cmd, + program, + status + ), + )) + } +} + +fn spawn(cmd: &mut Command, program: &str) -> Result<(Child, JoinHandle<()>), Error> { + println!("running: {:?}", cmd); + + // Capture the standard error coming from these programs, and write it out + // with cargo:warning= prefixes. Note that this is a bit wonky to avoid + // requiring the output to be UTF-8, we instead just ship bytes from one + // location to another. + match cmd.stderr(Stdio::piped()).spawn() { + Ok(mut child) => { + let stderr = BufReader::new(child.stderr.take().unwrap()); + let print = thread::spawn(move || for line in stderr.split(b'\n').filter_map( + |l| l.ok(), + ) + { + print!("cargo:warning="); + std::io::stdout().write_all(&line).unwrap(); + println!(""); + }); + Ok((child, print)) + } + Err(ref e) if e.kind() == io::ErrorKind::NotFound => { + let extra = if cfg!(windows) { + " (see https://github.com/alexcrichton/cc-rs#compile-time-requirements \ + for help)" + } else { + "" + }; + Err(Error::new( + ErrorKind::ToolNotFound, + &format!( + "Failed to find tool. Is `{}` installed?{}", + program, + extra + ), + )) + } + Err(_) => Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Command {:?} with args {:?} failed to start.", + cmd, + program + ), + )), + } +} + +fn fail(s: &str) -> ! { + panic!("\n\nInternal error occurred: {}\n\n", s) +} + + +fn command_add_output_file(cmd: &mut Command, dst: &Path, msvc: bool, is_asm: bool) { + if msvc && is_asm { + cmd.arg("/Fo").arg(dst); + } else if msvc { + let mut s = OsString::from("/Fo"); + s.push(&dst); + cmd.arg(s); + } else { + cmd.arg("-o").arg(&dst); + } +} diff --git a/cc-1.0.4/src/registry.rs b/cc-1.0.4/src/registry.rs new file mode 100644 index 000000000..a45272344 --- /dev/null +++ b/cc-1.0.4/src/registry.rs @@ -0,0 +1,190 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ffi::{OsString, OsStr}; +use std::io; +use std::ops::RangeFrom; +use std::os::raw; +use std::os::windows::prelude::*; + +pub struct RegistryKey(Repr); + +type HKEY = *mut u8; +type DWORD = u32; +type LPDWORD = *mut DWORD; +type LPCWSTR = *const u16; +type LPWSTR = *mut u16; +type LONG = raw::c_long; +type PHKEY = *mut HKEY; +type PFILETIME = *mut u8; +type LPBYTE = *mut u8; +type REGSAM = u32; + +const ERROR_SUCCESS: DWORD = 0; +const ERROR_NO_MORE_ITEMS: DWORD = 259; +const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY; +const REG_SZ: DWORD = 1; +const KEY_READ: DWORD = 0x20019; +const KEY_WOW64_32KEY: DWORD = 0x200; + +#[link(name = "advapi32")] +extern "system" { + fn RegOpenKeyExW(key: HKEY, + lpSubKey: LPCWSTR, + ulOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY) + -> LONG; + fn RegEnumKeyExW(key: HKEY, + dwIndex: DWORD, + lpName: LPWSTR, + lpcName: LPDWORD, + lpReserved: LPDWORD, + lpClass: LPWSTR, + lpcClass: LPDWORD, + lpftLastWriteTime: PFILETIME) + -> LONG; + fn RegQueryValueExW(hKey: HKEY, + lpValueName: LPCWSTR, + lpReserved: LPDWORD, + lpType: LPDWORD, + lpData: LPBYTE, + lpcbData: LPDWORD) + -> LONG; + fn RegCloseKey(hKey: HKEY) -> LONG; +} + +struct OwnedKey(HKEY); + +enum Repr { + Const(HKEY), + Owned(OwnedKey), +} + +pub struct Iter<'a> { + idx: RangeFrom, + key: &'a RegistryKey, +} + +unsafe impl Sync for Repr {} +unsafe impl Send for Repr {} + +pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE)); + +impl RegistryKey { + fn raw(&self) -> HKEY { + match self.0 { + Repr::Const(val) => val, + Repr::Owned(ref val) => val.0, + } + } + + pub fn open(&self, key: &OsStr) -> io::Result { + let key = key.encode_wide().chain(Some(0)).collect::>(); + let mut ret = 0 as *mut _; + let err = unsafe { + RegOpenKeyExW(self.raw(), + key.as_ptr(), + 0, + KEY_READ | KEY_WOW64_32KEY, + &mut ret) + }; + if err == ERROR_SUCCESS as LONG { + Ok(RegistryKey(Repr::Owned(OwnedKey(ret)))) + } else { + Err(io::Error::from_raw_os_error(err as i32)) + } + } + + pub fn iter(&self) -> Iter { + Iter { + idx: 0.., + key: self, + } + } + + pub fn query_str(&self, name: &str) -> io::Result { + let name: &OsStr = name.as_ref(); + let name = name.encode_wide().chain(Some(0)).collect::>(); + let mut len = 0; + let mut kind = 0; + unsafe { + let err = RegQueryValueExW(self.raw(), + name.as_ptr(), + 0 as *mut _, + &mut kind, + 0 as *mut _, + &mut len); + if err != ERROR_SUCCESS as LONG { + return Err(io::Error::from_raw_os_error(err as i32)); + } + if kind != REG_SZ { + return Err(io::Error::new(io::ErrorKind::Other, "registry key wasn't a string")); + } + + // The length here is the length in bytes, but we're using wide + // characters so we need to be sure to halve it for the capacity + // passed in. + let mut v = Vec::with_capacity(len as usize / 2); + let err = RegQueryValueExW(self.raw(), + name.as_ptr(), + 0 as *mut _, + 0 as *mut _, + v.as_mut_ptr() as *mut _, + &mut len); + if err != ERROR_SUCCESS as LONG { + return Err(io::Error::from_raw_os_error(err as i32)); + } + v.set_len(len as usize / 2); + + // Some registry keys may have a terminating nul character, but + // we're not interested in that, so chop it off if it's there. + if v[v.len() - 1] == 0 { + v.pop(); + } + Ok(OsString::from_wide(&v)) + } + } +} + +impl Drop for OwnedKey { + fn drop(&mut self) { + unsafe { + RegCloseKey(self.0); + } + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + self.idx.next().and_then(|i| unsafe { + let mut v = Vec::with_capacity(256); + let mut len = v.capacity() as DWORD; + let ret = RegEnumKeyExW(self.key.raw(), + i, + v.as_mut_ptr(), + &mut len, + 0 as *mut _, + 0 as *mut _, + 0 as *mut _, + 0 as *mut _); + if ret == ERROR_NO_MORE_ITEMS as LONG { + None + } else if ret != ERROR_SUCCESS as LONG { + Some(Err(io::Error::from_raw_os_error(ret as i32))) + } else { + v.set_len(len as usize); + Some(Ok(OsString::from_wide(&v))) + } + }) + } +} diff --git a/cc-1.0.4/src/setup_config.rs b/cc-1.0.4/src/setup_config.rs new file mode 100644 index 000000000..175b7f157 --- /dev/null +++ b/cc-1.0.4/src/setup_config.rs @@ -0,0 +1,257 @@ +// Copyright © 2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] +#![allow(unused)] + +use std::ffi::OsString; +use std::ptr::null_mut; +use winapi::Interface; +use winapi::{LPFILETIME, ULONG}; +use winapi::S_FALSE; +use winapi::BSTR; +use winapi::LPCOLESTR; +use winapi::{CLSCTX_ALL, CoCreateInstance}; +use winapi::LPSAFEARRAY; +use winapi::{IUnknown, IUnknownVtbl}; +use winapi::{HRESULT, LCID, LPCWSTR, PULONGLONG}; + +use com::{BStr, ComPtr}; + +// Bindings to the Setup.Configuration stuff +pub type InstanceState = u32; + +pub const eNone: InstanceState = 0; +pub const eLocal: InstanceState = 1; +pub const eRegistered: InstanceState = 2; +pub const eNoRebootRequired: InstanceState = 4; +pub const eComplete: InstanceState = -1i32 as u32; + +RIDL!{#[uuid(0xb41463c3, 0x8866, 0x43b5, 0xbc, 0x33, 0x2b, 0x06, 0x76, 0xf7, 0xf4, 0x2e)] +interface ISetupInstance(ISetupInstanceVtbl): IUnknown(IUnknownVtbl) { + fn GetInstanceId( + pbstrInstanceId: *mut BSTR, + ) -> HRESULT, + fn GetInstallDate( + pInstallDate: LPFILETIME, + ) -> HRESULT, + fn GetInstallationName( + pbstrInstallationName: *mut BSTR, + ) -> HRESULT, + fn GetInstallationPath( + pbstrInstallationPath: *mut BSTR, + ) -> HRESULT, + fn GetInstallationVersion( + pbstrInstallationVersion: *mut BSTR, + ) -> HRESULT, + fn GetDisplayName( + lcid: LCID, + pbstrDisplayName: *mut BSTR, + ) -> HRESULT, + fn GetDescription( + lcid: LCID, + pbstrDescription: *mut BSTR, + ) -> HRESULT, + fn ResolvePath( + pwszRelativePath: LPCOLESTR, + pbstrAbsolutePath: *mut BSTR, + ) -> HRESULT, +}} + +RIDL!{#[uuid(0x89143c9a, 0x05af, 0x49b0, 0xb7, 0x17, 0x72, 0xe2, 0x18, 0xa2, 0x18, 0x5c)] +interface ISetupInstance2(ISetupInstance2Vtbl): ISetupInstance(ISetupInstanceVtbl) { + fn GetState( + pState: *mut InstanceState, + ) -> HRESULT, + fn GetPackages( + ppsaPackages: *mut LPSAFEARRAY, + ) -> HRESULT, + fn GetProduct( + ppPackage: *mut *mut ISetupPackageReference, + ) -> HRESULT, + fn GetProductPath( + pbstrProductPath: *mut BSTR, + ) -> HRESULT, +}} + +RIDL!{#[uuid(0x6380bcff, 0x41d3, 0x4b2e, 0x8b, 0x2e, 0xbf, 0x8a, 0x68, 0x10, 0xc8, 0x48)] +interface IEnumSetupInstances(IEnumSetupInstancesVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut *mut ISetupInstance, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumSetupInstances, + ) -> HRESULT, +}} + +RIDL!{#[uuid(0x42843719, 0xdb4c, 0x46c2, 0x8e, 0x7c, 0x64, 0xf1, 0x81, 0x6e, 0xfd, 0x5b)] +interface ISetupConfiguration(ISetupConfigurationVtbl): IUnknown(IUnknownVtbl) { + fn EnumInstances( + ppEnumInstances: *mut *mut IEnumSetupInstances, + ) -> HRESULT, + fn GetInstanceForCurrentProcess( + ppInstance: *mut *mut ISetupInstance, + ) -> HRESULT, + fn GetInstanceForPath( + wzPath: LPCWSTR, + ppInstance: *mut *mut ISetupInstance, + ) -> HRESULT, +}} + +RIDL!{#[uuid(0x26aab78c, 0x4a60, 0x49d6, 0xaf, 0x3b, 0x3c, 0x35, 0xbc, 0x93, 0x36, 0x5d)] +interface ISetupConfiguration2(ISetupConfiguration2Vtbl): + ISetupConfiguration(ISetupConfigurationVtbl) { + fn EnumAllInstances( + ppEnumInstances: *mut *mut IEnumSetupInstances, + ) -> HRESULT, +}} + +RIDL!{#[uuid(0xda8d8a16, 0xb2b6, 0x4487, 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5)] +interface ISetupPackageReference(ISetupPackageReferenceVtbl): IUnknown(IUnknownVtbl) { + fn GetId( + pbstrId: *mut BSTR, + ) -> HRESULT, + fn GetVersion( + pbstrVersion: *mut BSTR, + ) -> HRESULT, + fn GetChip( + pbstrChip: *mut BSTR, + ) -> HRESULT, + fn GetLanguage( + pbstrLanguage: *mut BSTR, + ) -> HRESULT, + fn GetBranch( + pbstrBranch: *mut BSTR, + ) -> HRESULT, + fn GetType( + pbstrType: *mut BSTR, + ) -> HRESULT, + fn GetUniqueId( + pbstrUniqueId: *mut BSTR, + ) -> HRESULT, +}} + +RIDL!{#[uuid(0x42b21b78, 0x6192, 0x463e, 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c)] +interface ISetupHelper(ISetupHelperVtbl): IUnknown(IUnknownVtbl) { + fn ParseVersion( + pwszVersion: LPCOLESTR, + pullVersion: PULONGLONG, + ) -> HRESULT, + fn ParseVersionRange( + pwszVersionRange: LPCOLESTR, + pullMinVersion: PULONGLONG, + pullMaxVersion: PULONGLONG, + ) -> HRESULT, +}} + +DEFINE_GUID!{CLSID_SetupConfiguration, + 0x177f0c4a, 0x1cd3, 0x4de7, 0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d} + +// Safe wrapper around the COM interfaces +pub struct SetupConfiguration(ComPtr); + +impl SetupConfiguration { + pub fn new() -> Result { + let mut obj = null_mut(); + let err = unsafe { CoCreateInstance( + &CLSID_SetupConfiguration, null_mut(), CLSCTX_ALL, + &ISetupConfiguration::uuidof(), &mut obj, + ) }; + if err < 0 { return Err(err); } + let obj = unsafe { ComPtr::from_raw(obj as *mut ISetupConfiguration) }; + Ok(SetupConfiguration(obj)) + } + pub fn get_instance_for_current_process(&self) -> Result { + let mut obj = null_mut(); + let err = unsafe { self.0.GetInstanceForCurrentProcess(&mut obj) }; + if err < 0 { return Err(err); } + Ok(unsafe { SetupInstance::from_raw(obj) }) + } + pub fn enum_instances(&self) -> Result { + let mut obj = null_mut(); + let err = unsafe { self.0.EnumInstances(&mut obj) }; + if err < 0 { return Err(err); } + Ok(unsafe { EnumSetupInstances::from_raw(obj) }) + } + pub fn enum_all_instances(&self) -> Result { + let mut obj = null_mut(); + let this = try!(self.0.cast::()); + let err = unsafe { this.EnumAllInstances(&mut obj) }; + if err < 0 { return Err(err); } + Ok(unsafe { EnumSetupInstances::from_raw(obj) }) + } +} + +pub struct SetupInstance(ComPtr); + +impl SetupInstance { + pub unsafe fn from_raw(obj: *mut ISetupInstance) -> SetupInstance { + SetupInstance(ComPtr::from_raw(obj)) + } + pub fn instance_id(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstanceId(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { return Err(err); } + Ok(bstr.to_osstring()) + } + pub fn installation_name(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstallationName(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { return Err(err); } + Ok(bstr.to_osstring()) + } + pub fn installation_path(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstallationPath(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { return Err(err); } + Ok(bstr.to_osstring()) + } + pub fn installation_version(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstallationVersion(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { return Err(err); } + Ok(bstr.to_osstring()) + } + pub fn product_path(&self) -> Result { + let mut s = null_mut(); + let this = try!(self.0.cast::()); + let err = unsafe { this.GetProductPath(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { return Err(err); } + Ok(bstr.to_osstring()) + } +} + +pub struct EnumSetupInstances(ComPtr); + +impl EnumSetupInstances { + pub unsafe fn from_raw(obj: *mut IEnumSetupInstances) -> EnumSetupInstances { + EnumSetupInstances(ComPtr::from_raw(obj)) + } +} + +impl Iterator for EnumSetupInstances { + type Item = Result; + fn next(&mut self) -> Option> { + let mut obj = null_mut(); + let err = unsafe { self.0.Next(1, &mut obj, null_mut()) }; + if err < 0 { return Some(Err(err)); } + if err == S_FALSE { return None; } + Some(Ok(unsafe { SetupInstance::from_raw(obj) })) + } +} + diff --git a/cc-1.0.4/src/winapi.rs b/cc-1.0.4/src/winapi.rs new file mode 100644 index 000000000..3fb04087f --- /dev/null +++ b/cc-1.0.4/src/winapi.rs @@ -0,0 +1,214 @@ +// Copyright © 2015-2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] + +use std::os::raw; + +pub type wchar_t = u16; + +pub type UINT = raw::c_uint; +pub type LPUNKNOWN = *mut IUnknown; +pub type REFIID = *const IID; +pub type IID = GUID; +pub type REFCLSID = *const IID; +pub type PVOID = *mut raw::c_void; +pub type USHORT = raw::c_ushort; +pub type ULONG = raw::c_ulong; +pub type LONG = raw::c_long; +pub type DWORD = u32; +pub type LPVOID = *mut raw::c_void; +pub type HRESULT = raw::c_long; +pub type LPFILETIME = *mut FILETIME; +pub type BSTR = *mut OLECHAR; +pub type OLECHAR = WCHAR; +pub type WCHAR = wchar_t; +pub type LPCOLESTR = *const OLECHAR; +pub type LCID = DWORD; +pub type LPCWSTR = *const WCHAR; +pub type PULONGLONG = *mut ULONGLONG; +pub type ULONGLONG = u64; + +pub const S_OK: HRESULT = 0; +pub const S_FALSE: HRESULT = 1; +pub const COINIT_MULTITHREADED: u32 = 0x0; + +pub type CLSCTX = u32; + +pub const CLSCTX_INPROC_SERVER: CLSCTX = 0x1; +pub const CLSCTX_INPROC_HANDLER: CLSCTX = 0x2; +pub const CLSCTX_LOCAL_SERVER: CLSCTX = 0x4; +pub const CLSCTX_REMOTE_SERVER: CLSCTX = 0x10; + +pub const CLSCTX_ALL: CLSCTX = CLSCTX_INPROC_SERVER | + CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct GUID { + pub Data1: raw::c_ulong, + pub Data2: raw::c_ushort, + pub Data3: raw::c_ushort, + pub Data4: [raw::c_uchar; 8], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct FILETIME { + pub dwLowDateTime: DWORD, + pub dwHighDateTime: DWORD, +} + +pub trait Interface { + fn uuidof() -> GUID; +} + +#[link(name = "ole32")] +#[link(name = "oleaut32")] +extern { } + +extern "system" { + pub fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) -> HRESULT; + pub fn CoCreateInstance(rclsid: REFCLSID, pUnkOuter: LPUNKNOWN, + dwClsContext: DWORD, riid: REFIID, + ppv: *mut LPVOID) -> HRESULT; + pub fn SysFreeString(bstrString: BSTR); + pub fn SysStringLen(pbstr: BSTR) -> UINT; +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SAFEARRAYBOUND { + pub cElements: ULONG, + pub lLbound: LONG, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SAFEARRAY { + pub cDims: USHORT, + pub fFeatures: USHORT, + pub cbElements: ULONG, + pub cLocks: ULONG, + pub pvData: PVOID, + pub rgsabound: [SAFEARRAYBOUND; 1], +} + +pub type LPSAFEARRAY = *mut SAFEARRAY; + +macro_rules! DEFINE_GUID { + ( + $name:ident, $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr + ) => { + pub const $name: $crate::winapi::GUID = $crate::winapi::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + }; + } +} + +macro_rules! RIDL { + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + #[repr(C)] + pub struct $vtbl { + $(pub $method: unsafe extern "system" fn( + This: *mut $interface, + $($p: $t),* + ) -> $rtr,)+ + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}} + RIDL!{@uuid $interface $($uuid),+} + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) { + }) => ( + #[repr(C)] + pub struct $vtbl { + pub parent: $pvtbl, + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@deref $interface $pinterface} + RIDL!{@uuid $interface $($uuid),+} + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + #[repr(C)] + pub struct $vtbl { + pub parent: $pvtbl, + $(pub $method: unsafe extern "system" fn( + This: *mut $interface, + $($p: $t,)* + ) -> $rtr,)+ + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}} + RIDL!{@deref $interface $pinterface} + RIDL!{@uuid $interface $($uuid),+} + ); + (@deref $interface:ident $pinterface:ident) => ( + impl ::std::ops::Deref for $interface { + type Target = $pinterface; + #[inline] + fn deref(&self) -> &$pinterface { + unsafe { &*(self as *const $interface as *const $pinterface) } + } + } + ); + (@impl $interface:ident {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + impl $interface { + $(#[inline] pub unsafe fn $method(&self, $($p: $t,)*) -> $rtr { + ((*self.lpVtbl).$method)(self as *const _ as *mut _, $($p,)*) + })+ + } + ); + (@uuid $interface:ident + $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr + ) => ( + impl $crate::winapi::Interface for $interface { + #[inline] + fn uuidof() -> $crate::winapi::GUID { + $crate::winapi::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + } + } + } + ); +} + +RIDL!{#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IUnknown(IUnknownVtbl) { + fn QueryInterface( + riid: REFIID, + ppvObject: *mut *mut raw::c_void, + ) -> HRESULT, + fn AddRef() -> ULONG, + fn Release() -> ULONG, +}} diff --git a/cc-1.0.4/src/windows_registry.rs b/cc-1.0.4/src/windows_registry.rs new file mode 100644 index 000000000..9099e0f8d --- /dev/null +++ b/cc-1.0.4/src/windows_registry.rs @@ -0,0 +1,634 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A helper module to probe the Windows Registry when looking for +//! windows-specific tools. + +use std::process::Command; + +use Tool; + +#[cfg(windows)] +macro_rules! otry { + ($expr:expr) => (match $expr { + Some(val) => val, + None => return None, + }) +} + +/// Attempts to find a tool within an MSVC installation using the Windows +/// registry as a point to search from. +/// +/// The `target` argument is the target that the tool should work for (e.g. +/// compile or link for) and the `tool` argument is the tool to find (e.g. +/// `cl.exe` or `link.exe`). +/// +/// This function will return `None` if the tool could not be found, or it will +/// return `Some(cmd)` which represents a command that's ready to execute the +/// tool with the appropriate environment variables set. +/// +/// Note that this function always returns `None` for non-MSVC targets. +pub fn find(target: &str, tool: &str) -> Option { + find_tool(target, tool).map(|c| c.to_command()) +} + +/// Similar to the `find` function above, this function will attempt the same +/// operation (finding a MSVC tool in a local install) but instead returns a +/// `Tool` which may be introspected. +#[cfg(not(windows))] +pub fn find_tool(_target: &str, _tool: &str) -> Option { + None +} + +/// Documented above. +#[cfg(windows)] +pub fn find_tool(target: &str, tool: &str) -> Option { + use std::env; + + // This logic is all tailored for MSVC, if we're not that then bail out + // early. + if !target.contains("msvc") { + return None; + } + + // Looks like msbuild isn't located in the same location as other tools like + // cl.exe and lib.exe. To handle this we probe for it manually with + // dedicated registry keys. + if tool.contains("msbuild") { + return impl_::find_msbuild(target); + } + + // If VCINSTALLDIR is set, then someone's probably already run vcvars and we + // should just find whatever that indicates. + if env::var_os("VCINSTALLDIR").is_some() { + return env::var_os("PATH") + .and_then(|path| env::split_paths(&path).map(|p| p.join(tool)).find(|p| p.exists())) + .map(|path| Tool::new(path.into())); + } + + // Ok, if we're here, now comes the fun part of the probing. Default shells + // or shells like MSYS aren't really configured to execute `cl.exe` and the + // various compiler tools shipped as part of Visual Studio. Here we try to + // first find the relevant tool, then we also have to be sure to fill in + // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that + // the tool is actually usable. + + return impl_::find_msvc_15(tool, target) + .or_else(|| impl_::find_msvc_14(tool, target)) + .or_else(|| impl_::find_msvc_12(tool, target)) + .or_else(|| impl_::find_msvc_11(tool, target)); +} + +/// A version of Visual Studio +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum VsVers { + /// Visual Studio 12 (2013) + Vs12, + /// Visual Studio 14 (2015) + Vs14, + /// Visual Studio 15 (2017) + Vs15, + + /// Hidden variant that should not be matched on. Callers that want to + /// handle an enumeration of `VsVers` instances should always have a default + /// case meaning that it's a VS version they don't understand. + #[doc(hidden)] + #[allow(bad_style)] + __Nonexhaustive_do_not_match_this_or_your_code_will_break, +} + +/// Find the most recent installed version of Visual Studio +/// +/// This is used by the cmake crate to figure out the correct +/// generator. +#[cfg(not(windows))] +pub fn find_vs_version() -> Result { + Err(format!("not windows")) +} + +/// Documented above +#[cfg(windows)] +pub fn find_vs_version() -> Result { + use std::env; + + match env::var("VisualStudioVersion") { + Ok(version) => { + match &version[..] { + "15.0" => Ok(VsVers::Vs15), + "14.0" => Ok(VsVers::Vs14), + "12.0" => Ok(VsVers::Vs12), + vers => Err(format!("\n\n\ + unsupported or unknown VisualStudio version: {}\n\ + if another version is installed consider running \ + the appropriate vcvars script before building this \ + crate\n\ + ", vers)), + } + } + _ => { + // Check for the presense of a specific registry key + // that indicates visual studio is installed. + if impl_::has_msbuild_version("15.0") { + Ok(VsVers::Vs15) + } else if impl_::has_msbuild_version("14.0") { + Ok(VsVers::Vs14) + } else if impl_::has_msbuild_version("12.0") { + Ok(VsVers::Vs12) + } else { + Err(format!("\n\n\ + couldn't determine visual studio generator\n\ + if VisualStudio is installed, however, consider \ + running the appropriate vcvars script before building \ + this crate\n\ + ")) + } + } + } +} + +#[cfg(windows)] +mod impl_ { + use std::env; + use std::ffi::OsString; + use std::mem; + use std::path::{Path, PathBuf}; + use std::fs::File; + use std::io::Read; + use registry::{RegistryKey, LOCAL_MACHINE}; + use com; + use setup_config::{SetupConfiguration, SetupInstance}; + + use Tool; + + struct MsvcTool { + tool: PathBuf, + libs: Vec, + path: Vec, + include: Vec, + } + + impl MsvcTool { + fn new(tool: PathBuf) -> MsvcTool { + MsvcTool { + tool: tool, + libs: Vec::new(), + path: Vec::new(), + include: Vec::new(), + } + } + + fn into_tool(self) -> Tool { + let MsvcTool { tool, libs, path, include } = self; + let mut tool = Tool::new(tool.into()); + add_env(&mut tool, "LIB", libs); + add_env(&mut tool, "PATH", path); + add_env(&mut tool, "INCLUDE", include); + tool + } + } + + // In MSVC 15 (2017) MS once again changed the scheme for locating + // the tooling. Now we must go through some COM interfaces, which + // is super fun for Rust. + // + // Note that much of this logic can be found [online] wrt paths, COM, etc. + // + // [online]: https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/ + pub fn find_msvc_15(tool: &str, target: &str) -> Option { + otry!(com::initialize().ok()); + + let config = otry!(SetupConfiguration::new().ok()); + let iter = otry!(config.enum_all_instances().ok()); + for instance in iter { + let instance = otry!(instance.ok()); + let tool = tool_from_vs15_instance(tool, target, &instance); + if tool.is_some() { + return tool; + } + } + + None + } + + fn tool_from_vs15_instance(tool: &str, target: &str, + instance: &SetupInstance) -> Option { + let (bin_path, host_dylib_path, lib_path, include_path) = otry!(vs15_vc_paths(target, instance)); + let tool_path = bin_path.join(tool); + if !tool_path.exists() { return None }; + + let mut tool = MsvcTool::new(tool_path); + tool.path.push(host_dylib_path); + tool.libs.push(lib_path); + tool.include.push(include_path); + + if let Some((atl_lib_path, atl_include_path)) = atl_paths(target, &bin_path) { + tool.libs.push(atl_lib_path); + tool.include.push(atl_include_path); + } + + otry!(add_sdks(&mut tool, target)); + + Some(tool.into_tool()) + } + + fn vs15_vc_paths(target: &str, instance: &SetupInstance) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf)> { + let instance_path: PathBuf = otry!(instance.installation_path().ok()).into(); + let version_path = instance_path.join(r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt"); + let mut version_file = otry!(File::open(version_path).ok()); + let mut version = String::new(); + otry!(version_file.read_to_string(&mut version).ok()); + let version = version.trim(); + let host = match host_arch() { + X86 => "X86", + X86_64 => "X64", + _ => return None, + }; + let target = otry!(lib_subdir(target)); + // The directory layout here is MSVC/bin/Host$host/$target/ + let path = instance_path.join(r"VC\Tools\MSVC").join(version); + // This is the path to the toolchain for a particular target, running + // on a given host + let bin_path = path.join("bin").join(&format!("Host{}", host)).join(&target); + // But! we also need PATH to contain the target directory for the host + // architecture, because it contains dlls like mspdb140.dll compiled for + // the host architecture. + let host_dylib_path = path.join("bin").join(&format!("Host{}", host)).join(&host.to_lowercase()); + let lib_path = path.join("lib").join(&target); + let include_path = path.join("include"); + Some((bin_path, host_dylib_path, lib_path, include_path)) + } + + fn atl_paths(target: &str, path: &Path) -> Option<(PathBuf, PathBuf)> { + let atl_path = path.join("atlfmc"); + let sub = otry!(lib_subdir(target)); + if atl_path.exists() { + Some((atl_path.join("lib").join(sub), atl_path.join("include"))) + } else { + None + } + } + + // For MSVC 14 we need to find the Universal CRT as well as either + // the Windows 10 SDK or Windows 8.1 SDK. + pub fn find_msvc_14(tool: &str, target: &str) -> Option { + let vcdir = otry!(get_vc_dir("14.0")); + let mut tool = otry!(get_tool(tool, &vcdir, target)); + otry!(add_sdks(&mut tool, target)); + Some(tool.into_tool()) + } + + fn add_sdks(tool: &mut MsvcTool, target: &str) -> Option<()> { + let sub = otry!(lib_subdir(target)); + let (ucrt, ucrt_version) = otry!(get_ucrt_dir()); + + tool.path.push(ucrt.join("bin").join(&ucrt_version).join(sub)); + + let ucrt_include = ucrt.join("include").join(&ucrt_version); + tool.include.push(ucrt_include.join("ucrt")); + + let ucrt_lib = ucrt.join("lib").join(&ucrt_version); + tool.libs.push(ucrt_lib.join("ucrt").join(sub)); + + if let Some((sdk, version)) = get_sdk10_dir() { + tool.path.push(sdk.join("bin").join(sub)); + let sdk_lib = sdk.join("lib").join(&version); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk.join("include").join(&version); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + tool.include.push(sdk_include.join("shared")); + } else if let Some(sdk) = get_sdk81_dir() { + tool.path.push(sdk.join("bin").join(sub)); + let sdk_lib = sdk.join("lib").join("winv6.3"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk.join("include"); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + tool.include.push(sdk_include.join("shared")); + } + + Some(()) + } + + // For MSVC 12 we need to find the Windows 8.1 SDK. + pub fn find_msvc_12(tool: &str, target: &str) -> Option { + let vcdir = otry!(get_vc_dir("12.0")); + let mut tool = otry!(get_tool(tool, &vcdir, target)); + let sub = otry!(lib_subdir(target)); + let sdk81 = otry!(get_sdk81_dir()); + tool.path.push(sdk81.join("bin").join(sub)); + let sdk_lib = sdk81.join("lib").join("winv6.3"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk81.join("include"); + tool.include.push(sdk_include.join("shared")); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + Some(tool.into_tool()) + } + + // For MSVC 11 we need to find the Windows 8 SDK. + pub fn find_msvc_11(tool: &str, target: &str) -> Option { + let vcdir = otry!(get_vc_dir("11.0")); + let mut tool = otry!(get_tool(tool, &vcdir, target)); + let sub = otry!(lib_subdir(target)); + let sdk8 = otry!(get_sdk8_dir()); + tool.path.push(sdk8.join("bin").join(sub)); + let sdk_lib = sdk8.join("lib").join("win8"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk8.join("include"); + tool.include.push(sdk_include.join("shared")); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + Some(tool.into_tool()) + } + + fn add_env(tool: &mut Tool, env: &str, paths: Vec) { + let prev = env::var_os(env).unwrap_or(OsString::new()); + let prev = env::split_paths(&prev); + let new = paths.into_iter().chain(prev); + tool.env.push((env.to_string().into(), env::join_paths(new).unwrap())); + } + + // Given a possible MSVC installation directory, we look for the linker and + // then add the MSVC library path. + fn get_tool(tool: &str, path: &Path, target: &str) -> Option { + bin_subdir(target) + .into_iter() + .map(|(sub, host)| (path.join("bin").join(sub).join(tool), path.join("bin").join(host))) + .filter(|&(ref path, _)| path.is_file()) + .map(|(path, host)| { + let mut tool = MsvcTool::new(path); + tool.path.push(host); + tool + }) + .filter_map(|mut tool| { + let sub = otry!(vc_lib_subdir(target)); + tool.libs.push(path.join("lib").join(sub)); + tool.include.push(path.join("include")); + let atlmfc_path = path.join("atlmfc"); + if atlmfc_path.exists() { + tool.libs.push(atlmfc_path.join("lib").join(sub)); + tool.include.push(atlmfc_path.join("include")); + } + Some(tool) + }) + .next() + } + + // To find MSVC we look in a specific registry key for the version we are + // trying to find. + fn get_vc_dir(ver: &str) -> Option { + let key = r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let path = otry!(key.query_str(ver).ok()); + Some(path.into()) + } + + // To find the Universal CRT we look in a specific registry key for where + // all the Universal CRTs are located and then sort them asciibetically to + // find the newest version. While this sort of sorting isn't ideal, it is + // what vcvars does so that's good enough for us. + // + // Returns a pair of (root, version) for the ucrt dir if found + fn get_ucrt_dir() -> Option<(PathBuf, String)> { + let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let root = otry!(key.query_str("KitsRoot10").ok()); + let readdir = otry!(Path::new(&root).join("lib").read_dir().ok()); + let max_libdir = otry!(readdir.filter_map(|dir| dir.ok()) + .map(|dir| dir.path()) + .filter(|dir| { + dir.components() + .last() + .and_then(|c| c.as_os_str().to_str()) + .map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir()) + .unwrap_or(false) + }) + .max()); + let version = max_libdir.components().last().unwrap(); + let version = version.as_os_str().to_str().unwrap().to_string(); + Some((root.into(), version)) + } + + // Vcvars finds the correct version of the Windows 10 SDK by looking + // for the include `um\Windows.h` because sometimes a given version will + // only have UCRT bits without the rest of the SDK. Since we only care about + // libraries and not includes, we instead look for `um\x64\kernel32.lib`. + // Since the 32-bit and 64-bit libraries are always installed together we + // only need to bother checking x64, making this code a tiny bit simpler. + // Like we do for the Universal CRT, we sort the possibilities + // asciibetically to find the newest one as that is what vcvars does. + fn get_sdk10_dir() -> Option<(PathBuf, String)> { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let root = otry!(key.query_str("InstallationFolder").ok()); + let readdir = otry!(Path::new(&root).join("lib").read_dir().ok()); + let mut dirs = readdir.filter_map(|dir| dir.ok()) + .map(|dir| dir.path()) + .collect::>(); + dirs.sort(); + let dir = otry!(dirs.into_iter() + .rev() + .filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file()) + .next()); + let version = dir.components().last().unwrap(); + let version = version.as_os_str().to_str().unwrap().to_string(); + Some((root.into(), version)) + } + + // Interestingly there are several subdirectories, `win7` `win8` and + // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same + // applies to us. Note that if we were targetting kernel mode drivers + // instead of user mode applications, we would care. + fn get_sdk81_dir() -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let root = otry!(key.query_str("InstallationFolder").ok()); + Some(root.into()) + } + + fn get_sdk8_dir() -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0"; + let key = otry!(LOCAL_MACHINE.open(key.as_ref()).ok()); + let root = otry!(key.query_str("InstallationFolder").ok()); + Some(root.into()) + } + + const PROCESSOR_ARCHITECTURE_INTEL: u16 = 0; + const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9; + const X86: u16 = PROCESSOR_ARCHITECTURE_INTEL; + const X86_64: u16 = PROCESSOR_ARCHITECTURE_AMD64; + + // When choosing the tool to use, we have to choose the one which matches + // the target architecture. Otherwise we end up in situations where someone + // on 32-bit Windows is trying to cross compile to 64-bit and it tries to + // invoke the native 64-bit compiler which won't work. + // + // For the return value of this function, the first member of the tuple is + // the folder of the tool we will be invoking, while the second member is + // the folder of the host toolchain for that tool which is essential when + // using a cross linker. We return a Vec since on x64 there are often two + // linkers that can target the architecture we desire. The 64-bit host + // linker is preferred, and hence first, due to 64-bit allowing it more + // address space to work with and potentially being faster. + fn bin_subdir(target: &str) -> Vec<(&'static str, &'static str)> { + let arch = target.split('-').next().unwrap(); + match (arch, host_arch()) { + ("i586", X86) | ("i686", X86) => vec![("", "")], + ("i586", X86_64) | ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")], + ("x86_64", X86) => vec![("x86_amd64", "")], + ("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")], + ("arm", X86) => vec![("x86_arm", "")], + ("arm", X86_64) => vec![("amd64_arm", "amd64"), ("x86_arm", "")], + _ => vec![], + } + } + + fn lib_subdir(target: &str) -> Option<&'static str> { + let arch = target.split('-').next().unwrap(); + match arch { + "i586" | "i686" => Some("x86"), + "x86_64" => Some("x64"), + "arm" => Some("arm"), + _ => None, + } + } + + // MSVC's x86 libraries are not in a subfolder + fn vc_lib_subdir(target: &str) -> Option<&'static str> { + let arch = target.split('-').next().unwrap(); + match arch { + "i586" | "i686" => Some(""), + "x86_64" => Some("amd64"), + "arm" => Some("arm"), + _ => None, + } + } + + #[allow(bad_style)] + fn host_arch() -> u16 { + type DWORD = u32; + type WORD = u16; + type LPVOID = *mut u8; + type DWORD_PTR = usize; + + #[repr(C)] + struct SYSTEM_INFO { + wProcessorArchitecture: WORD, + _wReserved: WORD, + _dwPageSize: DWORD, + _lpMinimumApplicationAddress: LPVOID, + _lpMaximumApplicationAddress: LPVOID, + _dwActiveProcessorMask: DWORD_PTR, + _dwNumberOfProcessors: DWORD, + _dwProcessorType: DWORD, + _dwAllocationGranularity: DWORD, + _wProcessorLevel: WORD, + _wProcessorRevision: WORD, + } + + extern "system" { + fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO); + } + + unsafe { + let mut info = mem::zeroed(); + GetNativeSystemInfo(&mut info); + info.wProcessorArchitecture + } + } + + // Given a registry key, look at all the sub keys and find the one which has + // the maximal numeric value. + // + // Returns the name of the maximal key as well as the opened maximal key. + fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> { + let mut max_vers = 0; + let mut max_key = None; + for subkey in key.iter().filter_map(|k| k.ok()) { + let val = subkey.to_str() + .and_then(|s| s.trim_left_matches("v").replace(".", "").parse().ok()); + let val = match val { + Some(s) => s, + None => continue, + }; + if val > max_vers { + if let Ok(k) = key.open(&subkey) { + max_vers = val; + max_key = Some((subkey, k)); + } + } + } + max_key + } + + pub fn has_msbuild_version(version: &str) -> bool { + match version { + "15.0" => { + find_msbuild_vs15("x86_64-pc-windows-msvc").is_some() || + find_msbuild_vs15("i686-pc-windows-msvc").is_some() + } + "12.0" | "14.0" => { + LOCAL_MACHINE.open( + &OsString::from(format!("SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{}", + version))).is_ok() + } + _ => false + } + } + + // see http://stackoverflow.com/questions/328017/path-to-msbuild + pub fn find_msbuild(target: &str) -> Option { + // VS 15 (2017) changed how to locate msbuild + if let Some(r) = find_msbuild_vs15(target) { + return Some(r); + } else { + find_old_msbuild(target) + } + } + + fn find_msbuild_vs15(target: &str) -> Option { + // Seems like this could also go through SetupConfiguration, + // or that find_msvc_15 could just use this registry key + // instead of the COM interface. + let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7"; + LOCAL_MACHINE.open(key.as_ref()) + .ok() + .and_then(|key| { + key.query_str("15.0").ok() + }) + .map(|path| { + let path = PathBuf::from(path).join(r"MSBuild\15.0\Bin\MSBuild.exe"); + let mut tool = Tool::new(path); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + tool + }) + } + + fn find_old_msbuild(target: &str) -> Option { + let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions"; + LOCAL_MACHINE.open(key.as_ref()) + .ok() + .and_then(|key| { + max_version(&key).and_then(|(_vers, key)| key.query_str("MSBuildToolsPath").ok()) + }) + .map(|path| { + let mut path = PathBuf::from(path); + path.push("MSBuild.exe"); + let mut tool = Tool::new(path); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + tool + }) + } +} diff --git a/cc-1.0.4/tests/cc_env.rs b/cc-1.0.4/tests/cc_env.rs new file mode 100644 index 000000000..8ffe651a6 --- /dev/null +++ b/cc-1.0.4/tests/cc_env.rs @@ -0,0 +1,73 @@ +extern crate cc; +extern crate tempdir; + +use std::env; +use std::path::Path; +use std::ffi::OsString; + +mod support; +use support::Test; + +#[test] +fn main() { + ccache(); + distcc(); + ccache_spaces(); + ccache_env_flags(); +} + +fn ccache() { + let test = Test::gnu(); + + env::set_var("CC", "ccache cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn ccache_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn distcc() { + let test = Test::gnu(); + test.shim("distcc"); + + env::set_var("CC", "distcc cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn ccache_env_flags() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache lol-this-is-not-a-compiler"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("lol-this-is-not-a-compiler")); + assert_eq!( + compiler.cc_env(), + OsString::from("ccache lol-this-is-not-a-compiler") + ); + assert!( + compiler + .cflags_env() + .into_string() + .unwrap() + .contains("ccache") == false + ); + assert!( + compiler + .cflags_env() + .into_string() + .unwrap() + .contains(" lol-this-is-not-a-compiler") == false + ); + + env::set_var("CC", ""); +} diff --git a/cc-1.0.4/tests/support/mod.rs b/cc-1.0.4/tests/support/mod.rs new file mode 100644 index 000000000..bb56bf305 --- /dev/null +++ b/cc-1.0.4/tests/support/mod.rs @@ -0,0 +1,122 @@ +#![allow(dead_code)] + +use std::env; +use std::ffi::OsStr; +use std::fs::{self, File}; +use std::io::prelude::*; +use std::path::PathBuf; + +use cc; +use tempdir::TempDir; + +pub struct Test { + pub td: TempDir, + pub gcc: PathBuf, + pub msvc: bool, +} + +pub struct Execution { + args: Vec, +} + +impl Test { + pub fn new() -> Test { + let mut gcc = PathBuf::from(env::current_exe().unwrap()); + gcc.pop(); + if gcc.ends_with("deps") { + gcc.pop(); + } + gcc.push(format!("gcc-shim{}", env::consts::EXE_SUFFIX)); + Test { + td: TempDir::new("gcc-test").unwrap(), + gcc: gcc, + msvc: false, + } + } + + pub fn gnu() -> Test { + let t = Test::new(); + t.shim("cc").shim("c++").shim("ar"); + t + } + + pub fn msvc() -> Test { + let mut t = Test::new(); + t.shim("cl").shim("lib.exe"); + t.msvc = true; + t + } + + pub fn shim(&self, name: &str) -> &Test { + let fname = format!("{}{}", name, env::consts::EXE_SUFFIX); + fs::hard_link(&self.gcc, self.td.path().join(&fname)) + .or_else(|_| fs::copy(&self.gcc, self.td.path().join(&fname)).map(|_| ())) + .unwrap(); + self + } + + pub fn gcc(&self) -> cc::Build { + let mut cfg = cc::Build::new(); + let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::>(); + path.insert(0, self.td.path().to_owned()); + let target = if self.msvc { + "x86_64-pc-windows-msvc" + } else { + "x86_64-unknown-linux-gnu" + }; + + cfg.target(target) + .host(target) + .opt_level(2) + .debug(false) + .out_dir(self.td.path()) + .__set_env("PATH", env::join_paths(path).unwrap()) + .__set_env("GCCTEST_OUT_DIR", self.td.path()); + if self.msvc { + cfg.compiler(self.td.path().join("cl")); + cfg.archiver(self.td.path().join("lib.exe")); + } + cfg + } + + pub fn cmd(&self, i: u32) -> Execution { + let mut s = String::new(); + File::open(self.td.path().join(format!("out{}", i))) + .unwrap() + .read_to_string(&mut s) + .unwrap(); + Execution { args: s.lines().map(|s| s.to_string()).collect() } + } +} + +impl Execution { + pub fn must_have>(&self, p: P) -> &Execution { + if !self.has(p.as_ref()) { + panic!("didn't find {:?} in {:?}", p.as_ref(), self.args); + } else { + self + } + } + + pub fn must_not_have>(&self, p: P) -> &Execution { + if self.has(p.as_ref()) { + panic!("found {:?}", p.as_ref()); + } else { + self + } + } + + pub fn has(&self, p: &OsStr) -> bool { + self.args.iter().any(|arg| OsStr::new(arg) == p) + } + + pub fn must_have_in_order(&self, before: &str, after: &str) -> &Execution { + let before_position = self.args.iter().rposition(|x| OsStr::new(x) == OsStr::new(before)); + let after_position = self.args.iter().rposition(|x| OsStr::new(x) == OsStr::new(after)); + match (before_position, after_position) { + (Some(b), Some(a)) if b < a => {}, + (b, a) => { panic!("{:?} (last position: {:?}) did not appear before {:?} (last position: {:?})", before, b, after, a) }, + }; + self + } +} diff --git a/cc-1.0.4/tests/test.rs b/cc-1.0.4/tests/test.rs new file mode 100644 index 000000000..7e5a28d86 --- /dev/null +++ b/cc-1.0.4/tests/test.rs @@ -0,0 +1,351 @@ +extern crate cc; +extern crate tempdir; + +use support::Test; + +mod support; + +#[test] +fn gnu_smoke() { + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .compile("foo"); + + test.cmd(0) + .must_have("-O2") + .must_have("foo.c") + .must_not_have("-g") + .must_have("-c") + .must_have("-ffunction-sections") + .must_have("-fdata-sections"); + test.cmd(1).must_have(test.td.path().join("foo.o")); +} + +#[test] +fn gnu_opt_level_1() { + let test = Test::gnu(); + test.gcc() + .opt_level(1) + .file("foo.c") + .compile("foo"); + + test.cmd(0) + .must_have("-O1") + .must_not_have("-O2"); +} + +#[test] +fn gnu_opt_level_s() { + let test = Test::gnu(); + test.gcc() + .opt_level_str("s") + .file("foo.c") + .compile("foo"); + + test.cmd(0) + .must_have("-Os") + .must_not_have("-O1") + .must_not_have("-O2") + .must_not_have("-O3") + .must_not_have("-Oz"); +} + +#[test] +fn gnu_debug() { + let test = Test::gnu(); + test.gcc() + .debug(true) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("-g"); +} + +#[test] +fn gnu_warnings_into_errors() { + let test = Test::gnu(); + test.gcc() + .warnings_into_errors(true) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Werror"); +} + +#[test] +fn gnu_warnings() { + let test = Test::gnu(); + test.gcc() + .warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Wall") + .must_have("-Wextra"); +} + +#[test] +fn gnu_warnings_overridable() { + let test = Test::gnu(); + test.gcc() + .warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have_in_order("-Wall", "-Wno-missing-field-initializers"); +} + +#[test] +fn gnu_x86_64() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("x86_64-{}", vendor); + let test = Test::gnu(); + test.gcc() + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0) + .must_have("-fPIC") + .must_have("-m64"); + } +} + +#[test] +fn gnu_x86_64_no_pic() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("x86_64-{}", vendor); + let test = Test::gnu(); + test.gcc() + .pic(false) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-fPIC"); + } +} + +#[test] +fn gnu_i686() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("i686-{}", vendor); + let test = Test::gnu(); + test.gcc() + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0) + .must_have("-m32"); + } +} + +#[test] +fn gnu_i686_pic() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("i686-{}", vendor); + let test = Test::gnu(); + test.gcc() + .pic(true) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-fPIC"); + } +} + +#[test] +fn gnu_set_stdlib() { + let test = Test::gnu(); + test.gcc() + .cpp_set_stdlib(Some("foo")) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-stdlib=foo"); +} + +#[test] +fn gnu_include() { + let test = Test::gnu(); + test.gcc() + .include("foo/bar") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-I").must_have("foo/bar"); +} + +#[test] +fn gnu_define() { + let test = Test::gnu(); + test.gcc() + .define("FOO", "bar") + .define("BAR", None) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR"); +} + +#[test] +fn gnu_compile_assembly() { + let test = Test::gnu(); + test.gcc() + .file("foo.S") + .compile("foo"); + test.cmd(0).must_have("foo.S"); +} + +#[test] +fn gnu_shared() { + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .shared_flag(true) + .static_flag(false) + .compile("foo"); + + test.cmd(0) + .must_have("-shared") + .must_not_have("-static"); +} + +#[test] +fn gnu_flag_if_supported() { + if cfg!(windows) { + return + } + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .flag_if_supported("-Wall") + .flag_if_supported("-Wflag-does-not-exist") + .flag_if_supported("-std=c++11") + .compile("foo"); + + test.cmd(0) + .must_have("-Wall") + .must_not_have("-Wflag-does-not-exist") + .must_not_have("-std=c++11"); +} + +#[test] +fn gnu_flag_if_supported_cpp() { + if cfg!(windows) { + return + } + let test = Test::gnu(); + test.gcc() + .cpp(true) + .file("foo.cpp") + .flag_if_supported("-std=c++11") + .compile("foo"); + + test.cmd(0) + .must_have("-std=c++11"); +} + +#[test] +fn gnu_static() { + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .shared_flag(false) + .static_flag(true) + .compile("foo"); + + test.cmd(0) + .must_have("-static") + .must_not_have("-shared"); +} + +#[test] +fn msvc_smoke() { + let test = Test::msvc(); + test.gcc() + .file("foo.c") + .compile("foo"); + + test.cmd(0) + .must_have("/O2") + .must_have("foo.c") + .must_not_have("/Z7") + .must_have("/c") + .must_have("/MD"); + test.cmd(1).must_have(test.td.path().join("foo.o")); +} + +#[test] +fn msvc_opt_level_0() { + let test = Test::msvc(); + test.gcc() + .opt_level(0) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("/O2"); +} + +#[test] +fn msvc_debug() { + let test = Test::msvc(); + test.gcc() + .debug(true) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("/Z7"); +} + +#[test] +fn msvc_include() { + let test = Test::msvc(); + test.gcc() + .include("foo/bar") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("/I").must_have("foo/bar"); +} + +#[test] +fn msvc_define() { + let test = Test::msvc(); + test.gcc() + .define("FOO", "bar") + .define("BAR", None) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("/DFOO=bar").must_have("/DBAR"); +} + +#[test] +fn msvc_static_crt() { + let test = Test::msvc(); + test.gcc() + .static_crt(true) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("/MT"); +} + +#[test] +fn msvc_no_static_crt() { + let test = Test::msvc(); + test.gcc() + .static_crt(false) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("/MD"); +} diff --git a/cfg-if-0.1.2/.cargo-checksum.json b/cfg-if-0.1.2/.cargo-checksum.json new file mode 100644 index 000000000..ac55a2301 --- /dev/null +++ b/cfg-if-0.1.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"} \ No newline at end of file diff --git a/cfg-if-0.1.2/.travis.yml b/cfg-if-0.1.2/.travis.yml new file mode 100644 index 000000000..a52fad673 --- /dev/null +++ b/cfg-if-0.1.2/.travis.yml @@ -0,0 +1,23 @@ +language: rust +rust: + - stable + - beta + - nightly +sudo: false +before_script: + - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH +script: + - cargo build --verbose + - cargo test --verbose + - rustdoc --test README.md -L target/debug -L target/debug/deps + - cargo doc --no-deps +after_success: + - travis-cargo --only nightly doc-upload +env: + global: + secure: "TyMGH+sbPmKs9lKCziKShxWr3G6im0owEchVrbUChWnQIQv1WydXftFoEoUsVl6qZspjehWK1b1AsnIgCXK0HtEi4DnqLsxs0s36bOjfg5yHBT/pETTr6kcq7KAL4Be4GmI331k6gT1Oi0TPFp7Sg9xpiWsQqKIHA5Szk2wpFQ8=" + + +notifications: + email: + on_success: never diff --git a/cfg-if-0.1.2/Cargo.toml b/cfg-if-0.1.2/Cargo.toml new file mode 100644 index 000000000..7afa063d1 --- /dev/null +++ b/cfg-if-0.1.2/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "cfg-if" +version = "0.1.2" +authors = ["Alex Crichton "] +license = "MIT/Apache-2.0" +readme = "README.md" +repository = "https://github.com/alexcrichton/cfg-if" +homepage = "https://github.com/alexcrichton/cfg-if" +documentation = "http://alexcrichton.com/cfg-if" +description = """ +A macro to ergonomically define an item depending on a large number of #[cfg] +parameters. Structured like an if-else chain, the first matching branch is the +item that gets emitted. +""" diff --git a/cfg-if-0.1.2/LICENSE-APACHE b/cfg-if-0.1.2/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/cfg-if-0.1.2/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/cfg-if-0.1.2/LICENSE-MIT b/cfg-if-0.1.2/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/cfg-if-0.1.2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/cfg-if-0.1.2/README.md b/cfg-if-0.1.2/README.md new file mode 100644 index 000000000..e9859dadb --- /dev/null +++ b/cfg-if-0.1.2/README.md @@ -0,0 +1,44 @@ +# cfg-if + +[![Build Status](https://travis-ci.org/alexcrichton/cfg-if.svg?branch=master)](https://travis-ci.org/alexcrichton/cfg-if) + +[Documentation](http://alexcrichton.com/cfg-if) + +A macro to ergonomically define an item depending on a large number of #[cfg] +parameters. Structured like an if-else chain, the first matching branch is the +item that gets emitted. + +```toml +[dependencies] +cfg-if = "0.1" +``` + +## Example + +```rust +#[macro_use] +extern crate cfg_if; + +cfg_if! { + if #[cfg(unix)] { + fn foo() { /* unix specific functionality */ } + } else if #[cfg(target_pointer_width = "32")] { + fn foo() { /* non-unix, 32-bit functionality */ } + } else { + fn foo() { /* fallback implementation */ } + } +} + +fn main() { + foo(); +} +``` + +# License + +`cfg-if` is primarily distributed under the terms of both the MIT license and +the Apache License (Version 2.0), with portions covered by various BSD-like +licenses. + +See LICENSE-APACHE, and LICENSE-MIT for details. + diff --git a/cfg-if-0.1.2/src/lib.rs b/cfg-if-0.1.2/src/lib.rs new file mode 100644 index 000000000..563cda81f --- /dev/null +++ b/cfg-if-0.1.2/src/lib.rs @@ -0,0 +1,133 @@ +//! A macro for defining #[cfg] if-else statements. +//! +//! The macro provided by this crate, `cfg_if`, is similar to the `if/elif` C +//! preprocessor macro by allowing definition of a cascade of `#[cfg]` cases, +//! emitting the implementation which matches first. +//! +//! This allows you to conveniently provide a long list #[cfg]'d blocks of code +//! without having to rewrite each clause multiple times. +//! +//! # Example +//! +//! ``` +//! #[macro_use] +//! extern crate cfg_if; +//! +//! cfg_if! { +//! if #[cfg(unix)] { +//! fn foo() { /* unix specific functionality */ } +//! } else if #[cfg(target_pointer_width = "32")] { +//! fn foo() { /* non-unix, 32-bit functionality */ } +//! } else { +//! fn foo() { /* fallback implementation */ } +//! } +//! } +//! +//! # fn main() {} +//! ``` + +#![no_std] + +#![doc(html_root_url = "http://alexcrichton.com/cfg-if")] +#![deny(missing_docs)] +#![cfg_attr(test, deny(warnings))] + +#[macro_export] +macro_rules! cfg_if { + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + __cfg_if_items! { + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + }; + ( + if #[cfg($($i_met:meta),*)] { $($i_it:item)* } + $( + else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } + )* + ) => { + __cfg_if_items! { + () ; + ( ($($i_met),*) ($($i_it)*) ), + $( ( ($($e_met),*) ($($e_it)*) ), )* + ( () () ), + } + } +} + +#[macro_export] +#[doc(hidden)] +macro_rules! __cfg_if_items { + (($($not:meta,)*) ; ) => {}; + (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { + __cfg_if_apply! { cfg(all($($m,)* not(any($($not),*)))), $($it)* } + __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* } + } +} + +#[macro_export] +#[doc(hidden)] +macro_rules! __cfg_if_apply { + ($m:meta, $($it:item)*) => { + $(#[$m] $it)* + } +} + +#[cfg(test)] +mod tests { + cfg_if! { + if #[cfg(test)] { + use core::option::Option as Option2; + fn works1() -> Option2 { Some(1) } + } else { + fn works1() -> Option { None } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works2() -> bool { false } + } else if #[cfg(test)] { + fn works2() -> bool { true } + } else { + fn works2() -> bool { false } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works3() -> bool { false } + } else { + fn works3() -> bool { true } + } + } + + cfg_if! { + if #[cfg(test)] { + use core::option::Option as Option3; + fn works4() -> Option3 { Some(1) } + } + } + + cfg_if! { + if #[cfg(foo)] { + fn works5() -> bool { false } + } else if #[cfg(test)] { + fn works5() -> bool { true } + } + } + + #[test] + fn it_works() { + assert!(works1().is_some()); + assert!(works2()); + assert!(works3()); + assert!(works4().is_some()); + assert!(works5()); + } +} diff --git a/cfg-if-0.1.2/tests/xcrate.rs b/cfg-if-0.1.2/tests/xcrate.rs new file mode 100644 index 000000000..f42b87767 --- /dev/null +++ b/cfg-if-0.1.2/tests/xcrate.rs @@ -0,0 +1,17 @@ +#[macro_use] +extern crate cfg_if; + +cfg_if! { + if #[cfg(foo)] { + fn works() -> bool { false } + } else if #[cfg(test)] { + fn works() -> bool { true } + } else { + fn works() -> bool { false } + } +} + +#[test] +fn smoke() { + assert!(works()); +} diff --git a/cmake-0.1.29/.cargo-checksum.json b/cmake-0.1.29/.cargo-checksum.json new file mode 100644 index 000000000..01fc5fd37 --- /dev/null +++ b/cmake-0.1.29/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb"} \ No newline at end of file diff --git a/cmake-0.1.29/.travis.yml b/cmake-0.1.29/.travis.yml new file mode 100644 index 000000000..bcd71cbe8 --- /dev/null +++ b/cmake-0.1.29/.travis.yml @@ -0,0 +1,20 @@ +language: rust +rust: + - stable + - beta + - nightly +sudo: false +before_script: + - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH +script: + - cargo test --verbose + - cargo doc --no-deps +after_success: + - travis-cargo --only nightly doc-upload +env: + global: + secure: "IA467qqr1j0BpyTqG6hO8Kpt+EUDEjO1pBVhu4+L76/dygkQIwROgqdT7uXZqBPMjU6Rbi0wzGXXHJjbCWVTCjh7U/Q0bK2svtR8DKtM0o1Un/YftSUFt2p/WoiJ9PrkUjKh1rHuoyijpUqAls0JfIz8OdC45egT2SWDufljo+s=" + +notifications: + email: + on_success: never diff --git a/cmake-0.1.29/Cargo.toml b/cmake-0.1.29/Cargo.toml new file mode 100644 index 000000000..c3d525ce6 --- /dev/null +++ b/cmake-0.1.29/Cargo.toml @@ -0,0 +1,25 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "cmake" +version = "0.1.29" +authors = ["Alex Crichton "] +description = "A build dependency for running `cmake` to build a native library\n" +homepage = "https://github.com/alexcrichton/cmake-rs" +documentation = "http://alexcrichton.com/cmake-rs" +readme = "README.md" +keywords = ["build-dependencies"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/cmake-rs" +[dependencies.cc] +version = "1.0" diff --git a/cmake-0.1.29/LICENSE-APACHE b/cmake-0.1.29/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/cmake-0.1.29/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/cmake-0.1.29/LICENSE-MIT b/cmake-0.1.29/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/cmake-0.1.29/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/cmake-0.1.29/README.md b/cmake-0.1.29/README.md new file mode 100644 index 000000000..07453382b --- /dev/null +++ b/cmake-0.1.29/README.md @@ -0,0 +1,34 @@ +# cmake + +[![Build Status](https://travis-ci.org/alexcrichton/cmake-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/cmake-rs) + +[Documentation](http://alexcrichton.com/cmake-rs) + +A build dependency for running the `cmake` build tool to compile a native +library. + +```toml +# Cargo.toml +[build-dependencies] +cmake = "0.2" +``` + +The CMake executable is assumed to be `cmake` unless the `CMAKE` +environmental variable is set. + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/cmake-0.1.29/src/lib.rs b/cmake-0.1.29/src/lib.rs new file mode 100644 index 000000000..c1836b2f7 --- /dev/null +++ b/cmake-0.1.29/src/lib.rs @@ -0,0 +1,633 @@ +//! A build dependency for running `cmake` to build a native library +//! +//! This crate provides some necessary boilerplate and shim support for running +//! the system `cmake` command to build a native library. It will add +//! appropriate cflags for building code to link into Rust, handle cross +//! compilation, and use the necessary generator for the platform being +//! targeted. +//! +//! The builder-style configuration allows for various variables and such to be +//! passed down into the build as well. +//! +//! ## Installation +//! +//! Add this to your `Cargo.toml`: +//! +//! ```toml +//! [build-dependencies] +//! cmake = "0.1" +//! ``` +//! +//! ## Examples +//! +//! ```no_run +//! use cmake; +//! +//! // Builds the project in the directory located in `libfoo`, installing it +//! // into $OUT_DIR +//! let dst = cmake::build("libfoo"); +//! +//! println!("cargo:rustc-link-search=native={}", dst.display()); +//! println!("cargo:rustc-link-lib=static=foo"); +//! ``` +//! +//! ```no_run +//! use cmake::Config; +//! +//! let dst = Config::new("libfoo") +//! .define("FOO", "BAR") +//! .cflag("-foo") +//! .build(); +//! println!("cargo:rustc-link-search=native={}", dst.display()); +//! println!("cargo:rustc-link-lib=static=foo"); +//! ``` + +#![deny(missing_docs)] + +extern crate cc; + +use std::env; +use std::ffi::{OsString, OsStr}; +use std::fs::{self, File}; +use std::io::ErrorKind; +use std::io::prelude::*; +use std::path::{Path, PathBuf}; +use std::process::Command; + +/// Builder style configuration for a pending CMake build. +pub struct Config { + path: PathBuf, + generator: Option, + cflags: OsString, + cxxflags: OsString, + defines: Vec<(OsString, OsString)>, + deps: Vec, + target: Option, + host: Option, + out_dir: Option, + profile: Option, + build_args: Vec, + cmake_target: Option, + env: Vec<(OsString, OsString)>, + static_crt: Option, + uses_cxx11: bool, +} + +/// Builds the native library rooted at `path` with the default cmake options. +/// This will return the directory in which the library was installed. +/// +/// # Examples +/// +/// ```no_run +/// use cmake; +/// +/// // Builds the project in the directory located in `libfoo`, installing it +/// // into $OUT_DIR +/// let dst = cmake::build("libfoo"); +/// +/// println!("cargo:rustc-link-search=native={}", dst.display()); +/// println!("cargo:rustc-link-lib=static=foo"); +/// ``` +/// +pub fn build>(path: P) -> PathBuf { + Config::new(path.as_ref()).build() +} + +impl Config { + /// Creates a new blank set of configuration to build the project specified + /// at the path `path`. + pub fn new>(path: P) -> Config { + Config { + path: env::current_dir().unwrap().join(path), + generator: None, + cflags: OsString::new(), + cxxflags: OsString::new(), + defines: Vec::new(), + deps: Vec::new(), + profile: None, + out_dir: None, + target: None, + host: None, + build_args: Vec::new(), + cmake_target: None, + env: Vec::new(), + static_crt: None, + uses_cxx11: false + } + } + + /// Sets the build-tool generator (`-G`) for this compilation. + pub fn generator>(&mut self, generator: T) -> &mut Config { + self.generator = Some(generator.as_ref().to_owned()); + self + } + + /// Adds a custom flag to pass down to the C compiler, supplementing those + /// that this library already passes. + pub fn cflag>(&mut self, flag: P) -> &mut Config { + self.cflags.push(" "); + self.cflags.push(flag.as_ref()); + self + } + + /// Adds a custom flag to pass down to the C++ compiler, supplementing those + /// that this library already passes. + pub fn cxxflag>(&mut self, flag: P) -> &mut Config { + self.cxxflags.push(" "); + self.cxxflags.push(flag.as_ref()); + self + } + + /// Adds a new `-D` flag to pass to cmake during the generation step. + pub fn define(&mut self, k: K, v: V) -> &mut Config + where K: AsRef, V: AsRef + { + self.defines.push((k.as_ref().to_owned(), v.as_ref().to_owned())); + self + } + + /// Registers a dependency for this compilation on the native library built + /// by Cargo previously. + /// + /// This registration will modify the `CMAKE_PREFIX_PATH` environment + /// variable for the build system generation step. + pub fn register_dep(&mut self, dep: &str) -> &mut Config { + self.deps.push(dep.to_string()); + self + } + + /// Sets the target triple for this compilation. + /// + /// This is automatically scraped from `$TARGET` which is set for Cargo + /// build scripts so it's not necessary to call this from a build script. + pub fn target(&mut self, target: &str) -> &mut Config { + self.target = Some(target.to_string()); + self + } + + /// Sets the host triple for this compilation. + /// + /// This is automatically scraped from `$HOST` which is set for Cargo + /// build scripts so it's not necessary to call this from a build script. + pub fn host(&mut self, host: &str) -> &mut Config { + self.host = Some(host.to_string()); + self + } + + /// Sets the output directory for this compilation. + /// + /// This is automatically scraped from `$OUT_DIR` which is set for Cargo + /// build scripts so it's not necessary to call this from a build script. + pub fn out_dir>(&mut self, out: P) -> &mut Config { + self.out_dir = Some(out.as_ref().to_path_buf()); + self + } + + /// Sets the profile for this compilation. + /// + /// This is automatically scraped from `$PROFILE` which is set for Cargo + /// build scripts so it's not necessary to call this from a build script. + pub fn profile(&mut self, profile: &str) -> &mut Config { + self.profile = Some(profile.to_string()); + self + } + + /// Configures whether the /MT flag or the /MD flag will be passed to msvc build tools. + /// + /// This option defaults to `false`, and affect only msvc targets. + pub fn static_crt(&mut self, static_crt: bool) -> &mut Config { + self.static_crt = Some(static_crt); + self + } + + /// Add an argument to the final `cmake` build step + pub fn build_arg>(&mut self, arg: A) -> &mut Config { + self.build_args.push(arg.as_ref().to_owned()); + self + } + + /// Configure an environment variable for the `cmake` processes spawned by + /// this crate in the `build` step. + pub fn env(&mut self, key: K, value: V) -> &mut Config + where K: AsRef, + V: AsRef, + { + self.env.push((key.as_ref().to_owned(), value.as_ref().to_owned())); + self + } + + /// Sets the build target for the final `cmake` build step, this will + /// default to "install" if not specified. + pub fn build_target(&mut self, target: &str) -> &mut Config { + self.cmake_target = Some(target.to_string()); + self + } + + /// Alters the default target triple on OSX to ensure that c++11 is + /// available. Does not change the target triple if it is explicitly + /// specified. + /// + /// This does not otherwise affect any CXX flags, i.e. it does not set + /// -std=c++11 or -stdlib=libc++. + pub fn uses_cxx11(&mut self) -> &mut Config { + self.uses_cxx11 = true; + self + } + + /// Run this configuration, compiling the library with all the configured + /// options. + /// + /// This will run both the build system generator command as well as the + /// command to build the library. + pub fn build(&mut self) -> PathBuf { + let target = match self.target.clone() { + Some(t) => t, + None => { + let mut t = getenv_unwrap("TARGET"); + if t.ends_with("-darwin") && self.uses_cxx11 { + t = t + "11" + } + t + } + }; + let host = self.host.clone().unwrap_or_else(|| { + getenv_unwrap("HOST") + }); + let msvc = target.contains("msvc"); + let mut c_cfg = cc::Build::new(); + c_cfg.cargo_metadata(false) + .opt_level(0) + .debug(false) + .target(&target) + .warnings(false) + .host(&host); + let mut cxx_cfg = cc::Build::new(); + cxx_cfg.cargo_metadata(false) + .cpp(true) + .opt_level(0) + .debug(false) + .target(&target) + .warnings(false) + .host(&host); + if let Some(static_crt) = self.static_crt { + c_cfg.static_crt(static_crt); + cxx_cfg.static_crt(static_crt); + } + let c_compiler = c_cfg.get_compiler(); + let cxx_compiler = cxx_cfg.get_compiler(); + + let dst = self.out_dir.clone().unwrap_or_else(|| { + PathBuf::from(getenv_unwrap("OUT_DIR")) + }); + let build = dst.join("build"); + self.maybe_clear(&build); + let _ = fs::create_dir(&build); + + // Add all our dependencies to our cmake paths + let mut cmake_prefix_path = Vec::new(); + for dep in &self.deps { + if let Some(root) = env::var_os(&format!("DEP_{}_ROOT", dep)) { + cmake_prefix_path.push(PathBuf::from(root)); + } + } + let system_prefix = env::var_os("CMAKE_PREFIX_PATH") + .unwrap_or(OsString::new()); + cmake_prefix_path.extend(env::split_paths(&system_prefix) + .map(|s| s.to_owned())); + let cmake_prefix_path = env::join_paths(&cmake_prefix_path).unwrap(); + + // Build up the first cmake command to build the build system. + let executable = env::var("CMAKE").unwrap_or("cmake".to_owned()); + let mut cmd = Command::new(executable); + cmd.arg(&self.path) + .current_dir(&build); + if target.contains("windows-gnu") { + if host.contains("windows") { + // On MinGW we need to coerce cmake to not generate a visual + // studio build system but instead use makefiles that MinGW can + // use to build. + if self.generator.is_none() { + cmd.arg("-G").arg("MSYS Makefiles"); + } + } else { + // If we're cross compiling onto windows, then set some + // variables which will hopefully get things to succeed. Some + // systems may need the `windres` or `dlltool` variables set, so + // set them if possible. + if !self.defined("CMAKE_SYSTEM_NAME") { + cmd.arg("-DCMAKE_SYSTEM_NAME=Windows"); + } + if !self.defined("CMAKE_RC_COMPILER") { + let exe = find_exe(c_compiler.path()); + if let Some(name) = exe.file_name().unwrap().to_str() { + let name = name.replace("gcc", "windres"); + let windres = exe.with_file_name(name); + if windres.is_file() { + let mut arg = OsString::from("-DCMAKE_RC_COMPILER="); + arg.push(&windres); + cmd.arg(arg); + } + } + } + } + } else if msvc { + // If we're on MSVC we need to be sure to use the right generator or + // otherwise we won't get 32/64 bit correct automatically. + // This also guarantees that NMake generator isn't chosen implicitly. + if self.generator.is_none() { + cmd.arg("-G").arg(self.visual_studio_generator(&target)); + } + } else if target.contains("redox") { + if !self.defined("CMAKE_SYSTEM_NAME") { + cmd.arg("-DCMAKE_SYSTEM_NAME=Generic"); + } + } + let mut is_ninja = false; + if let Some(ref generator) = self.generator { + cmd.arg("-G").arg(generator); + is_ninja = generator.to_string_lossy().contains("Ninja"); + } + let profile = self.profile.clone().unwrap_or_else(|| { + match &getenv_unwrap("PROFILE")[..] { + "bench" | "release" => "Release", + _ => "Debug", + }.to_string() + }); + for &(ref k, ref v) in &self.defines { + let mut os = OsString::from("-D"); + os.push(k); + os.push("="); + os.push(v); + cmd.arg(os); + } + + if !self.defined("CMAKE_INSTALL_PREFIX") { + let mut dstflag = OsString::from("-DCMAKE_INSTALL_PREFIX="); + dstflag.push(&dst); + cmd.arg(dstflag); + } + + let build_type = self.defines.iter().find(|&&(ref a, _)| { + a == "CMAKE_BUILD_TYPE" + }).map(|x| x.1.to_str().unwrap()).unwrap_or(&profile); + let build_type_upcase = build_type.chars() + .flat_map(|c| c.to_uppercase()) + .collect::(); + + { + // let cmake deal with optimization/debuginfo + let skip_arg = |arg: &OsStr| { + match arg.to_str() { + Some(s) => { + s.starts_with("-O") || s.starts_with("/O") || s == "-g" + } + None => false, + } + }; + let mut set_compiler = |kind: &str, + compiler: &cc::Tool, + extra: &OsString| { + let flag_var = format!("CMAKE_{}_FLAGS", kind); + let tool_var = format!("CMAKE_{}_COMPILER", kind); + if !self.defined(&flag_var) { + let mut flagsflag = OsString::from("-D"); + flagsflag.push(&flag_var); + flagsflag.push("="); + flagsflag.push(extra); + for arg in compiler.args() { + if skip_arg(arg) { + continue + } + flagsflag.push(" "); + flagsflag.push(arg); + } + cmd.arg(flagsflag); + } + + // The visual studio generator apparently doesn't respect + // `CMAKE_C_FLAGS` but does respect `CMAKE_C_FLAGS_RELEASE` and + // such. We need to communicate /MD vs /MT, so set those vars + // here. + // + // Note that for other generators, though, this *overrides* + // things like the optimization flags, which is bad. + if self.generator.is_none() && msvc { + let flag_var_alt = format!("CMAKE_{}_FLAGS_{}", kind, + build_type_upcase); + if !self.defined(&flag_var_alt) { + let mut flagsflag = OsString::from("-D"); + flagsflag.push(&flag_var_alt); + flagsflag.push("="); + flagsflag.push(extra); + for arg in compiler.args() { + if skip_arg(arg) { + continue + } + flagsflag.push(" "); + flagsflag.push(arg); + } + cmd.arg(flagsflag); + } + } + + // Apparently cmake likes to have an absolute path to the + // compiler as otherwise it sometimes thinks that this variable + // changed as it thinks the found compiler, /usr/bin/cc, + // differs from the specified compiler, cc. Not entirely sure + // what's up, but at least this means cmake doesn't get + // confused? + // + // Also specify this on Windows only if we use MSVC with Ninja, + // as it's not needed for MSVC with Visual Studio generators and + // for MinGW it doesn't really vary. + if !self.defined("CMAKE_TOOLCHAIN_FILE") + && !self.defined(&tool_var) + && (env::consts::FAMILY != "windows" || (msvc && is_ninja)) { + let mut ccompiler = OsString::from("-D"); + ccompiler.push(&tool_var); + ccompiler.push("="); + ccompiler.push(find_exe(compiler.path())); + #[cfg(windows)] { + // CMake doesn't like unescaped `\`s in compiler paths + // so we either have to escape them or replace with `/`s. + use std::os::windows::ffi::{OsStrExt, OsStringExt}; + let wchars = ccompiler.encode_wide().map(|wchar| { + if wchar == b'\\' as u16 { '/' as u16 } else { wchar } + }).collect::>(); + ccompiler = OsString::from_wide(&wchars); + } + cmd.arg(ccompiler); + } + }; + + set_compiler("C", &c_compiler, &self.cflags); + set_compiler("CXX", &cxx_compiler, &self.cxxflags); + } + + if !self.defined("CMAKE_BUILD_TYPE") { + cmd.arg(&format!("-DCMAKE_BUILD_TYPE={}", profile)); + } + + if !self.defined("CMAKE_TOOLCHAIN_FILE") { + if let Ok(s) = env::var("CMAKE_TOOLCHAIN_FILE") { + cmd.arg(&format!("-DCMAKE_TOOLCHAIN_FILE={}", s)); + } + } + + for &(ref k, ref v) in c_compiler.env().iter().chain(&self.env) { + cmd.env(k, v); + } + + run(cmd.env("CMAKE_PREFIX_PATH", cmake_prefix_path), "cmake"); + + let mut makeflags = None; + let mut parallel_args = Vec::new(); + if let Ok(s) = env::var("NUM_JOBS") { + match self.generator.as_ref().map(|g| g.to_string_lossy()) { + Some(ref g) if g.contains("Ninja") => { + parallel_args.push(format!("-j{}", s)); + } + Some(ref g) if g.contains("Visual Studio") => { + parallel_args.push(format!("/m:{}", s)); + } + Some(ref g) if g.contains("NMake") => { + // NMake creates `Makefile`s, but doesn't understand `-jN`. + } + _ if fs::metadata(&dst.join("build/Makefile")).is_ok() => { + match env::var_os("CARGO_MAKEFLAGS") { + // Only do this on non-windows as we could actually be + // invoking make instead of mingw32-make which doesn't + // work with our jobserver + Some(ref s) if !cfg!(windows) => makeflags = Some(s.clone()), + + // This looks like `make`, let's hope it understands `-jN`. + _ => parallel_args.push(format!("-j{}", s)), + } + } + _ => {} + } + } + + // And build! + let target = self.cmake_target.clone().unwrap_or("install".to_string()); + let mut cmd = Command::new("cmake"); + for &(ref k, ref v) in c_compiler.env().iter().chain(&self.env) { + cmd.env(k, v); + } + if let Some(flags) = makeflags { + cmd.env("MAKEFLAGS", flags); + } + run(cmd.arg("--build").arg(".") + .arg("--target").arg(target) + .arg("--config").arg(&profile) + .arg("--").args(&self.build_args) + .args(¶llel_args) + .current_dir(&build), "cmake"); + + println!("cargo:root={}", dst.display()); + return dst + } + + fn visual_studio_generator(&self, target: &str) -> String { + use cc::windows_registry::{find_vs_version, VsVers}; + + let base = match find_vs_version() { + Ok(VsVers::Vs15) => "Visual Studio 15 2017", + Ok(VsVers::Vs14) => "Visual Studio 14 2015", + Ok(VsVers::Vs12) => "Visual Studio 12 2013", + Ok(_) => panic!("Visual studio version detected but this crate \ + doesn't know how to generate cmake files for it, \ + can the `cmake` crate be updated?"), + Err(msg) => panic!(msg), + }; + if target.contains("i686") { + base.to_string() + } else if target.contains("x86_64") { + format!("{} Win64", base) + } else { + panic!("unsupported msvc target: {}", target); + } + } + + fn defined(&self, var: &str) -> bool { + self.defines.iter().any(|&(ref a, _)| a == var) + } + + // If a cmake project has previously been built (e.g. CMakeCache.txt already + // exists), then cmake will choke if the source directory for the original + // project being built has changed. Detect this situation through the + // `CMAKE_HOME_DIRECTORY` variable that cmake emits and if it doesn't match + // we blow away the build directory and start from scratch (the recommended + // solution apparently [1]). + // + // [1]: https://cmake.org/pipermail/cmake/2012-August/051545.html + fn maybe_clear(&self, dir: &Path) { + // CMake will apparently store canonicalized paths which normally + // isn't relevant to us but we canonicalize it here to ensure + // we're both checking the same thing. + let path = fs::canonicalize(&self.path).unwrap_or(self.path.clone()); + let mut f = match File::open(dir.join("CMakeCache.txt")) { + Ok(f) => f, + Err(..) => return, + }; + let mut u8contents = Vec::new(); + match f.read_to_end(&mut u8contents) { + Ok(f) => f, + Err(..) => return, + }; + let contents = String::from_utf8_lossy(&u8contents); + drop(f); + for line in contents.lines() { + if line.starts_with("CMAKE_HOME_DIRECTORY") { + let needs_cleanup = match line.split('=').next_back() { + Some(cmake_home) => { + fs::canonicalize(cmake_home) + .ok() + .map(|cmake_home| cmake_home != path) + .unwrap_or(true) + }, + None => true + }; + if needs_cleanup { + println!("detected home dir change, cleaning out entire build \ + directory"); + fs::remove_dir_all(dir).unwrap(); + } + break + } + } + } +} + +fn run(cmd: &mut Command, program: &str) { + println!("running: {:?}", cmd); + let status = match cmd.status() { + Ok(status) => status, + Err(ref e) if e.kind() == ErrorKind::NotFound => { + fail(&format!("failed to execute command: {}\nis `{}` not installed?", + e, program)); + } + Err(e) => fail(&format!("failed to execute command: {}", e)), + }; + if !status.success() { + fail(&format!("command did not execute successfully, got: {}", status)); + } +} + +fn find_exe(path: &Path) -> PathBuf { + env::split_paths(&env::var_os("PATH").unwrap_or(OsString::new())) + .map(|p| p.join(path)) + .find(|p| fs::metadata(p).is_ok()) + .unwrap_or(path.to_owned()) +} + +fn getenv_unwrap(v: &str) -> String { + match env::var(v) { + Ok(s) => s, + Err(..) => fail(&format!("environment variable `{}` not defined", v)), + } +} + +fn fail(s: &str) -> ! { + panic!("\n{}\n\nbuild script failed, must exit now", s) +} diff --git a/commoncrypto-0.2.0/.cargo-checksum.json b/commoncrypto-0.2.0/.cargo-checksum.json new file mode 100644 index 000000000..05b5c1366 --- /dev/null +++ b/commoncrypto-0.2.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007"} \ No newline at end of file diff --git a/commoncrypto-0.2.0/Cargo.toml b/commoncrypto-0.2.0/Cargo.toml new file mode 100644 index 000000000..cb62f9b59 --- /dev/null +++ b/commoncrypto-0.2.0/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "commoncrypto" +version = "0.2.0" +authors = ["Mark Lee"] +description = "Idiomatic Rust wrappers for Mac OS X's CommonCrypto library" +documentation = "https://docs.rs/commoncrypto" +repository = "https://github.com/malept/rust-commoncrypto" +keywords = ["crypto", "hash", "digest", "osx", "commoncrypto"] +license = "MIT" + +[features] +lint = ["clippy"] + +[dependencies] +commoncrypto-sys = { version = "0.2.0", path = "../commoncrypto-sys" } + +clippy = { version = "0.0", optional = true } + +[dev-dependencies] +hex = "0.2" diff --git a/commoncrypto-0.2.0/src/hash.rs b/commoncrypto-0.2.0/src/hash.rs new file mode 100644 index 000000000..a30ee4d15 --- /dev/null +++ b/commoncrypto-0.2.0/src/hash.rs @@ -0,0 +1,127 @@ +// Copyright (c) 2016 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//! Idiomatic Rust wrapper for `CommonCrypto`'s `CCDigestCtx` struct. + +use commoncrypto_sys::{CCDigestCreate, CCDigestCtx, CCDigestDestroy, CCDigestFinal, + CCDigestGetOutputSizeFromRef, CCDigestReset, CCDigestUpdate}; +use std::io; + +pub use commoncrypto_sys::CCDigestAlgorithm; + +const MAX_DIGEST_SIZE: usize = 64; + +macro_rules! err_from_ccdigest_retval{ + ($func_name: expr, $val: expr) => { + Err(io::Error::new(io::ErrorKind::Other, + format!("{} returned nonzero: {}", $func_name, $val))) + } +} + +#[derive(PartialEq, Copy, Clone, Debug)] +enum State { + Reset, + Updated, + Finalized, +} + +/// Generates cryptographic hashes. +#[derive(Debug)] +pub struct Hasher { + ctx: *mut CCDigestCtx, + state: State, +} + +impl Hasher { + /// Creates a new `Hasher` which will use the given cryptographic `algorithm`. + pub fn new(algorithm: CCDigestAlgorithm) -> Hasher { + let ctx: *mut CCDigestCtx; + unsafe { + ctx = CCDigestCreate(algorithm); + } + Hasher { + ctx: ctx, + state: State::Reset, + } + } + + fn init(&mut self) { + match self.state { + State::Reset => return, + State::Updated => { + let _ = self.finish(); + } + State::Finalized => (), + } + unsafe { CCDigestReset(self.ctx) }; + self.state = State::Reset; + } + + /// Feeds data into the hasher. + pub fn update(&mut self, data: &[u8]) -> io::Result { + if self.state == State::Finalized { + self.init(); + } + let result = unsafe { CCDigestUpdate(self.ctx, data.as_ptr() as *mut _, data.len()) }; + if result == 0 { + self.state = State::Updated; + Ok(data.len()) + } else { + err_from_ccdigest_retval!("CCDigestCreate", result) + } + } + + /// Finalizes digest operations and produces the digest output. + pub fn finish(&mut self) -> io::Result> { + if self.state == State::Finalized { + self.init(); + } + let expected_len = unsafe { CCDigestGetOutputSizeFromRef(self.ctx) }; + let mut md = vec![0; MAX_DIGEST_SIZE]; + let result = unsafe { CCDigestFinal(self.ctx, md.as_mut_ptr()) }; + if result == 0 { + self.state = State::Finalized; + md.truncate(expected_len); + Ok(md) + } else { + err_from_ccdigest_retval!("CCDigestFinal", result) + } + } +} + +impl io::Write for Hasher { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + self.update(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Drop for Hasher { + fn drop(&mut self) { + if self.state != State::Finalized { + let _ = self.finish(); + } + unsafe { CCDigestDestroy(self.ctx) } + } +} diff --git a/commoncrypto-0.2.0/src/lib.rs b/commoncrypto-0.2.0/src/lib.rs new file mode 100644 index 000000000..3b58f915e --- /dev/null +++ b/commoncrypto-0.2.0/src/lib.rs @@ -0,0 +1,30 @@ +// Copyright (c) 2016 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//! Idiomatic Rust wrappers for `CommonCrypto` structs. + +#![warn(missing_docs)] + +extern crate commoncrypto_sys; + +#[warn(missing_docs)] +pub mod hash; +#[warn(missing_docs)] +pub mod pbkdf2; diff --git a/commoncrypto-0.2.0/src/pbkdf2.rs b/commoncrypto-0.2.0/src/pbkdf2.rs new file mode 100644 index 000000000..94cb937c6 --- /dev/null +++ b/commoncrypto-0.2.0/src/pbkdf2.rs @@ -0,0 +1,66 @@ +// Copyright (c) 2016 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//! Idiomatic Rust wrapper for `CommonCrypto`'s `CCKeyDerivationPBKDF` function. + +use commoncrypto_sys::{CCKeyDerivationPBKDF, CCPBKDFAlgorithm}; + +use std::io; + +pub use commoncrypto_sys::CCPseudoRandomAlgorithm; + +macro_rules! err_from_cckeyderivationpbkdf_retval { + ($func_name: expr, $val: expr) => {{ + let kind = match $val { + // kCCParamError is the only one that's specifically noted + -43000 => io::ErrorKind::InvalidInput, + _ => io::ErrorKind::Other, + }; + + Err(io::Error::new(kind, format!("{} returned nonzero: {}", $func_name, $val))) + }} +} + +/// Derive a key from a password or passphrase and a salt +pub fn pbkdf2(password: &[u8], + salt: &[u8], + prf: CCPseudoRandomAlgorithm, + rounds: u32, + key_len: usize) + -> io::Result> { + let mut pw_derived = vec![0u8; key_len]; + let result = unsafe { + CCKeyDerivationPBKDF(CCPBKDFAlgorithm::kCCPBKDF2, + password.as_ptr(), + password.len(), + salt.as_ptr(), + salt.len(), + prf, + rounds, + pw_derived.as_mut_ptr(), + pw_derived.len()) + }; + + if result == 0 { + Ok(pw_derived) + } else { + err_from_cckeyderivationpbkdf_retval!("CCKeyDerivationPBKDF", result) + } +} diff --git a/commoncrypto-0.2.0/tests/hash.rs b/commoncrypto-0.2.0/tests/hash.rs new file mode 100644 index 000000000..bccc86c4c --- /dev/null +++ b/commoncrypto-0.2.0/tests/hash.rs @@ -0,0 +1,18 @@ +extern crate commoncrypto; +extern crate hex; + +use commoncrypto::hash::{CCDigestAlgorithm, Hasher}; +use hex::ToHex; +use std::io::Write; + +const TO_HASH: &'static str = "The quick brown fox jumps over the lazy dog"; +const TO_HASH_MD5: &'static str = "9e107d9d372bb6826bd81d3542a419d6"; + +#[test] +fn md5_hasher() { + let mut hasher = Hasher::new(CCDigestAlgorithm::kCCDigestMD5); + assert!(hasher.write_all(TO_HASH.as_bytes()).is_ok()); + let result = hasher.finish(); + assert!(result.is_ok()); + assert_eq!(result.expect("Hash failed").to_hex(), TO_HASH_MD5) +} diff --git a/commoncrypto-0.2.0/tests/pbkdf2.rs b/commoncrypto-0.2.0/tests/pbkdf2.rs new file mode 100644 index 000000000..179c5aec6 --- /dev/null +++ b/commoncrypto-0.2.0/tests/pbkdf2.rs @@ -0,0 +1,16 @@ +extern crate commoncrypto; +extern crate hex; + +use commoncrypto::pbkdf2::{pbkdf2, CCPseudoRandomAlgorithm}; +use hex::ToHex; + +#[test] +fn derive_pbkdf2() { + let derived = pbkdf2(b"password", + b"salt", + CCPseudoRandomAlgorithm::kCCPRFHmacAlgSHA1, + 1, + 20) + .unwrap(); + assert_eq!("0c60c80f961f0e71f3a9b524af6012062fe037a6", derived.to_hex()); +} diff --git a/commoncrypto-sys-0.2.0/.cargo-checksum.json b/commoncrypto-sys-0.2.0/.cargo-checksum.json new file mode 100644 index 000000000..6ad6734e2 --- /dev/null +++ b/commoncrypto-sys-0.2.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2"} \ No newline at end of file diff --git a/commoncrypto-sys-0.2.0/Cargo.toml b/commoncrypto-sys-0.2.0/Cargo.toml new file mode 100644 index 000000000..309cc8684 --- /dev/null +++ b/commoncrypto-sys-0.2.0/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "commoncrypto-sys" +version = "0.2.0" +authors = ["Mark Lee"] +description = "FFI bindings to Mac OS X's CommonCrypto library" +documentation = "https://docs.rs/commoncrypto-sys" +repository = "https://github.com/malept/rust-commoncrypto" +keywords = ["crypto", "hash", "digest", "osx", "commoncrypto"] +license = "MIT" + +[features] +lint = ["clippy"] + +[dependencies] +libc = "0.2" + +clippy = { version = "0.0", optional = true } + +[dev-dependencies] +hex = "0.2" diff --git a/commoncrypto-sys-0.2.0/src/lib.rs b/commoncrypto-sys-0.2.0/src/lib.rs new file mode 100644 index 000000000..dce335a3a --- /dev/null +++ b/commoncrypto-sys-0.2.0/src/lib.rs @@ -0,0 +1,237 @@ +// Copyright (c) 2016 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//! Low-level bindings to OSX/macOS/iOS's `CommonCrypto` library. + +#![warn(missing_docs)] + +extern crate libc; + +use libc::{c_int, c_uint}; + +/// Total number of operations. +const MD5_CBLOCK: usize = 64; +/// Number of operations per round. +const MD5_LBLOCK: usize = MD5_CBLOCK / 4; +/// Number of bytes for an MD5 hash. +pub const MD5_DIGEST_LENGTH: usize = 16; + +const SHA_LBLOCK: usize = 16; +/// Number of bytes for an SHA1 hash. +pub const SHA1_DIGEST_LENGTH: usize = 20; +/// Number of bytes for an SHA256 hash. +pub const SHA256_DIGEST_LENGTH: usize = 32; +/// Number of bytes for an SHA384 hash. +pub const SHA384_DIGEST_LENGTH: usize = 48; +/// Number of bytes for an SHA512 hash. +pub const SHA512_DIGEST_LENGTH: usize = 64; + +/// Struct used to generate MD5 hashes. +#[allow(non_camel_case_types, non_snake_case)] +#[derive(Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct CC_MD5_CTX { + A: c_uint, + B: c_uint, + C: c_uint, + D: c_uint, + Nl: c_uint, + Nh: c_uint, + data: [c_uint; MD5_LBLOCK], + num: c_uint, +} + +/// Struct used to generate SHA1 hashes. +#[allow(non_camel_case_types, non_snake_case)] +#[derive(Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct CC_SHA_CTX { + h0: c_uint, + h1: c_uint, + h2: c_uint, + h3: c_uint, + h4: c_uint, + Nl: c_uint, + Nh: c_uint, + data: [c_uint; SHA_LBLOCK], + num: c_uint, +} + +macro_rules! cc_sha2_struct { + ($ctx_name: ident, $ty: ty) => { + /// Struct used to generate SHA2 hashes with the given bits. + #[allow(non_camel_case_types, non_snake_case)] + #[derive(Clone, Debug, Default, PartialEq)] + #[repr(C)] + pub struct $ctx_name { + count: [$ty; 2], + hash: [$ty; 8], + wbuf: [$ty; 16], + } + } +} + +cc_sha2_struct!(CC_SHA256_CTX, u32); +cc_sha2_struct!(CC_SHA512_CTX, u64); + +/// Digest algorithm used in `CCDigest*()` functions. +#[repr(C)] +pub enum CCDigestAlgorithm { + /// No digest algorithm + kCCDigestNone = 0, + /// MD2 + kCCDigestMD2 = 1, + /// MD4 + kCCDigestMD4 = 2, + /// MD5 + kCCDigestMD5 = 3, + /// RIPEMD-128 + kCCDigestRMD128 = 4, + /// RIPEMD-160 + kCCDigestRMD160 = 5, + /// RIPEMD-256 + kCCDigestRMD256 = 6, + /// RIPEMD-320 + kCCDigestRMD320 = 7, + /// SHA1 + kCCDigestSHA1 = 8, + /// SHA224 + kCCDigestSHA224 = 9, + /// SHA256 + kCCDigestSHA256 = 10, + /// SHA384 + kCCDigestSHA384 = 11, + /// SHA512 + kCCDigestSHA512 = 12, + /// Skein, 128 bit (Deprecated in iPhoneOS 6.0 and MacOSX10.9) + kCCDigestSkein128 = 13, + /// Skein, 160 bit (Deprecated in iPhoneOS 6.0 and MacOSX10.9) + kCCDigestSkein160 = 14, + /// Skein, 224 bit (Deprecated in iPhoneOS 6.0 and MacOSX10.9) + kCCDigestSkein224 = 16, + /// Skein, 256 bit (Deprecated in iPhoneOS 6.0 and MacOSX10.9) + kCCDigestSkein256 = 17, + /// Skein, 384 bit (Deprecated in iPhoneOS 6.0 and MacOSX10.9) + kCCDigestSkein384 = 18, + /// Skein, 512 bit (Deprecated in iPhoneOS 6.0 and MacOSX10.9) + kCCDigestSkein512 = 19, +} + +const CC_DIGEST_SIZE: usize = 1032; + +/// Context used in `CCDigest*()` functions. +#[allow(non_camel_case_types, non_snake_case)] +#[repr(C)] +pub struct CCDigestCtx { + context: [u8; CC_DIGEST_SIZE], +} + +/// Algorithm for use with `CCKeyDerivationPBKDF()`. +#[repr(C)] +pub enum CCPBKDFAlgorithm { + /// PBKDF2 + kCCPBKDF2 = 2, +} + +/// Pseudo-random algorithm to use with `CCKeyDerivationPBKDF()`. +#[repr(C)] +pub enum CCPseudoRandomAlgorithm { + /// SHA-1 + kCCPRFHmacAlgSHA1 = 1, + /// SHA-224 + kCCPRFHmacAlgSHA224 = 2, + /// SHA-256 + kCCPRFHmacAlgSHA256 = 3, + /// SHA-384 + kCCPRFHmacAlgSHA384 = 4, + /// SHA-512 + kCCPRFHmacAlgSHA512 = 5, +} + +extern "C" { + /// Initializes MD5 hasher. See `man 3cc CC_MD5` for details. + pub fn CC_MD5_Init(ctx: *mut CC_MD5_CTX) -> c_int; + /// Appends data to be hashed. See `man 3cc CC_MD5` for details. + pub fn CC_MD5_Update(ctx: *mut CC_MD5_CTX, data: *const u8, n: usize) -> c_int; + /// Generates MD5 hash. See `man 3cc CC_MD5` for details. + pub fn CC_MD5_Final(md: *mut u8, ctx: *mut CC_MD5_CTX) -> c_int; + /// Initializes SHA1 hasher. See `man 3cc CC_SHA` for details. + pub fn CC_SHA1_Init(ctx: *mut CC_SHA_CTX) -> c_int; + /// Appends data to be hashed. See `man 3cc CC_SHA` for details. + pub fn CC_SHA1_Update(ctx: *mut CC_SHA_CTX, data: *const u8, n: usize) -> c_int; + /// Generates SHA1 hash. See `man 3cc CC_SHA` for details. + pub fn CC_SHA1_Final(md: *mut u8, ctx: *mut CC_SHA_CTX) -> c_int; + /// Initializes SHA256 hasher. See `man 3cc CC_SHA` for details. + pub fn CC_SHA256_Init(ctx: *mut CC_SHA256_CTX) -> c_int; + /// Appends data to be hashed. See `man 3cc CC_SHA` for details. + pub fn CC_SHA256_Update(ctx: *mut CC_SHA256_CTX, data: *const u8, n: usize) -> c_int; + /// Generates SHA256 hash. See `man 3cc CC_SHA` for details. + pub fn CC_SHA256_Final(md: *mut u8, ctx: *mut CC_SHA256_CTX) -> c_int; + /// Initializes SHA384 hasher. See `man 3cc CC_SHA` for details. + pub fn CC_SHA384_Init(ctx: *mut CC_SHA512_CTX) -> c_int; + /// Appends data to be hashed. See `man 3cc CC_SHA` for details. + pub fn CC_SHA384_Update(ctx: *mut CC_SHA512_CTX, data: *const u8, n: usize) -> c_int; + /// Generates SHA384 hash. See `man 3cc CC_SHA` for details. + pub fn CC_SHA384_Final(md: *mut u8, ctx: *mut CC_SHA512_CTX) -> c_int; + /// Initializes SHA512 hasher. See `man 3cc CC_SHA` for details. + pub fn CC_SHA512_Init(ctx: *mut CC_SHA512_CTX) -> c_int; + /// Appends data to be hashed. See `man 3cc CC_SHA` for details. + pub fn CC_SHA512_Update(ctx: *mut CC_SHA512_CTX, data: *const u8, n: usize) -> c_int; + /// Generates SHA512 hash. See `man 3cc CC_SHA` for details. + pub fn CC_SHA512_Final(md: *mut u8, ctx: *mut CC_SHA512_CTX) -> c_int; + /// Generic digest hasher. + pub fn CCDigest(algorithm: CCDigestAlgorithm, + data: *const u8, + length: usize, + output: *mut u8) + -> c_int; + /// Allocate and initialize a `CCDigestCtx` for a digest. + pub fn CCDigestCreate(algorithm: CCDigestAlgorithm) -> *mut CCDigestCtx; + /// Continue to digest data. Returns `0` on success. + pub fn CCDigestUpdate(ctx: *mut CCDigestCtx, data: *const u8, length: usize) -> c_int; + /// Conclude digest operations and produce the digest output. Returns `0` on success. + pub fn CCDigestFinal(ctx: *mut CCDigestCtx, output: *mut u8) -> c_int; + /// Clear and free a `CCDigestCtx`. + pub fn CCDigestDestroy(ctx: *mut CCDigestCtx); + /// Clear and re-initialize a `CCDigestCtx` for the same algorithm. + pub fn CCDigestReset(ctx: *mut CCDigestCtx); + /// Produce the digest output result for the bytes currently processed. Returns `0` on success. + pub fn CCDigestGetDigest(ctx: *mut CCDigestCtx, output: *mut u8) -> c_int; + /// Provides the block size of the digest algorithm. Returns `0` on failure. + pub fn CCDigestGetBlockSize(algorithm: CCDigestAlgorithm) -> usize; + /// Provides the digest output size of the digest algorithm. Returns `0` on failure. + pub fn CCDigestGetOutputSize(algorithm: CCDigestAlgorithm) -> usize; + /// Provides the block size of the digest algorithm. Returns `0` on failure. + pub fn CCDigestGetBlockSizeFromRef(ctx: *mut CCDigestCtx) -> usize; + /// Provides the digest output size of the digest algorithm. Returns `0` on failure. + pub fn CCDigestGetOutputSizeFromRef(ctx: *mut CCDigestCtx) -> usize; + + /// Derive a key from a user-supplied password via PBKDF2. + pub fn CCKeyDerivationPBKDF(algorithm: CCPBKDFAlgorithm, + password: *const u8, + passwordLen: usize, + salt: *const u8, + saltLen: usize, + prf: CCPseudoRandomAlgorithm, + rounds: u32, + derivedKey: *mut u8, + derivedKeyLen: usize) + -> c_int; +} diff --git a/commoncrypto-sys-0.2.0/tests/hash.rs b/commoncrypto-sys-0.2.0/tests/hash.rs new file mode 100644 index 000000000..b41ea5497 --- /dev/null +++ b/commoncrypto-sys-0.2.0/tests/hash.rs @@ -0,0 +1,138 @@ +extern crate commoncrypto_sys; +extern crate hex; + +use hex::ToHex; + +const TO_HASH: &'static str = "The quick brown fox jumps over the lazy dog"; +const TO_HASH_MD5: &'static str = "9e107d9d372bb6826bd81d3542a419d6"; +const TO_HASH_SHA1: &'static str = "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12"; +const TO_HASH_SHA256: &'static str = "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"; +const TO_HASH_SHA384: &'static str = "ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1"; +const TO_HASH_SHA512: &'static str = "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6"; + +macro_rules! test_cc_hash { + ( + $test_name: ident, + $ctx_ty: ident, + $digest_len: ident, + $init_func: ident, + $update_func: ident, + $final_func: ident, + $expected_hash: ident + ) => { + #[test] + fn $test_name() { + let mut ctx = commoncrypto_sys::$ctx_ty::default(); + let mut md = [0u8; commoncrypto_sys::$digest_len]; + unsafe { + assert_eq!(commoncrypto_sys::$init_func(&mut ctx), 1); + assert_eq!(commoncrypto_sys::$update_func(&mut ctx, TO_HASH.as_ptr(), TO_HASH.len()), 1); + assert_eq!(commoncrypto_sys::$final_func(md.as_mut_ptr(), &mut ctx), 1); + } + assert_eq!(md.to_vec().to_hex(), $expected_hash); + } + } +} + +macro_rules! test_ccdigest { + ( + $test_name: ident, + $algorithm: ident, + $digest_len: ident, + $expected_hash: ident + ) => { + #[test] + fn $test_name() { + let mut md = [0u8; commoncrypto_sys::$digest_len]; + unsafe { + assert_eq!(commoncrypto_sys::CCDigest(commoncrypto_sys::CCDigestAlgorithm::$algorithm, + TO_HASH.as_ptr(), + TO_HASH.len(), + md.as_mut_ptr()), 0) + } + assert_eq!(md.to_vec().to_hex(), $expected_hash); + } + } +} + +macro_rules! test_ccdigestgetoutputsize { + ( + $test_name: ident, + $algorithm: ident, + $expected_digest_len: ident + ) => { + #[test] + fn $test_name() { + unsafe { + assert_eq!(commoncrypto_sys::CCDigestGetOutputSize(commoncrypto_sys::CCDigestAlgorithm::$algorithm), + commoncrypto_sys::$expected_digest_len); + } + } + } +} + +test_cc_hash!(md5_hash, + CC_MD5_CTX, + MD5_DIGEST_LENGTH, + CC_MD5_Init, + CC_MD5_Update, + CC_MD5_Final, + TO_HASH_MD5); +test_cc_hash!(sha1_hash, + CC_SHA_CTX, + SHA1_DIGEST_LENGTH, + CC_SHA1_Init, + CC_SHA1_Update, + CC_SHA1_Final, + TO_HASH_SHA1); +test_cc_hash!(sha256_hash, + CC_SHA256_CTX, + SHA256_DIGEST_LENGTH, + CC_SHA256_Init, + CC_SHA256_Update, + CC_SHA256_Final, + TO_HASH_SHA256); +test_cc_hash!(sha384_hash, + CC_SHA512_CTX, + SHA384_DIGEST_LENGTH, + CC_SHA384_Init, + CC_SHA384_Update, + CC_SHA384_Final, + TO_HASH_SHA384); +test_cc_hash!(sha512_hash, + CC_SHA512_CTX, + SHA512_DIGEST_LENGTH, + CC_SHA512_Init, + CC_SHA512_Update, + CC_SHA512_Final, + TO_HASH_SHA512); + +test_ccdigest!(md5_ccdigest, kCCDigestMD5, MD5_DIGEST_LENGTH, TO_HASH_MD5); +test_ccdigest!(sha1_ccdigest, + kCCDigestSHA1, + SHA1_DIGEST_LENGTH, + TO_HASH_SHA1); +test_ccdigest!(sha256_ccdigest, + kCCDigestSHA256, + SHA256_DIGEST_LENGTH, + TO_HASH_SHA256); +test_ccdigest!(sha384_ccdigest, + kCCDigestSHA384, + SHA384_DIGEST_LENGTH, + TO_HASH_SHA384); +test_ccdigest!(sha512_ccdigest, + kCCDigestSHA512, + SHA512_DIGEST_LENGTH, + TO_HASH_SHA512); + +test_ccdigestgetoutputsize!(md5_ccdigestoutputsize, kCCDigestMD5, MD5_DIGEST_LENGTH); +test_ccdigestgetoutputsize!(sha1_ccdigestoutputsize, kCCDigestSHA1, SHA1_DIGEST_LENGTH); +test_ccdigestgetoutputsize!(sha256_ccdigestoutputsize, + kCCDigestSHA256, + SHA256_DIGEST_LENGTH); +test_ccdigestgetoutputsize!(sha384_ccdigestoutputsize, + kCCDigestSHA384, + SHA384_DIGEST_LENGTH); +test_ccdigestgetoutputsize!(sha512_ccdigestoutputsize, + kCCDigestSHA512, + SHA512_DIGEST_LENGTH); diff --git a/commoncrypto-sys-0.2.0/tests/pbkdf2.rs b/commoncrypto-sys-0.2.0/tests/pbkdf2.rs new file mode 100644 index 000000000..743a49a83 --- /dev/null +++ b/commoncrypto-sys-0.2.0/tests/pbkdf2.rs @@ -0,0 +1,48 @@ +extern crate commoncrypto_sys; +extern crate hex; + +use hex::{ToHex, FromHex}; + +// These password, salts, rounds and derived key values come from the test +// vectors stated in RFC 6070 +const PASSWORD: &'static str = "password"; +const SALT: &'static str = "salt"; + +const DERIVED1: &'static str = "0c60c80f961f0e71f3a9b524af6012062fe037a6"; +const DERIVED4096: &'static str = "4b007901b765489abead49d926f721d065a429c1"; + +macro_rules! test_pbkdf2 { + ( + $test_name: ident, + $prf_algorithm: ident, + $pw: ident, + $salt: ident, + $rounds: expr, + $expected_dkey: ident + ) => { + #[test] + fn $test_name() { + let derived_len = Vec::::from_hex($expected_dkey).expect("dkey from hex").len(); + let mut pw_derived = vec![0u8; derived_len]; + unsafe { + assert_eq!(0, commoncrypto_sys::CCKeyDerivationPBKDF( + commoncrypto_sys::CCPBKDFAlgorithm::kCCPBKDF2, + $pw.as_ptr(), $pw.len(), + $salt.as_ptr(), $salt.len(), + commoncrypto_sys::CCPseudoRandomAlgorithm::$prf_algorithm, + $rounds, + pw_derived.as_mut_ptr(), pw_derived.len() + )); + } + assert_eq!($expected_dkey, pw_derived.to_hex()); + } + } +} + +test_pbkdf2!(pbkdf2_1, kCCPRFHmacAlgSHA1, PASSWORD, SALT, 1, DERIVED1); +test_pbkdf2!(pbkdf2_4096, + kCCPRFHmacAlgSHA1, + PASSWORD, + SALT, + 4096, + DERIVED4096); diff --git a/core-foundation-0.4.6/.cargo-checksum.json b/core-foundation-0.4.6/.cargo-checksum.json new file mode 100644 index 000000000..afdc14e7c --- /dev/null +++ b/core-foundation-0.4.6/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"8047f547cd6856d45b1cdd75ef8d2f21f3d0e4bf1dab0a0041b0ae9a5dda9c0e"} \ No newline at end of file diff --git a/core-foundation-0.4.6/Cargo.toml b/core-foundation-0.4.6/Cargo.toml new file mode 100644 index 000000000..6c3ff250a --- /dev/null +++ b/core-foundation-0.4.6/Cargo.toml @@ -0,0 +1,39 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "core-foundation" +version = "0.4.6" +authors = ["The Servo Project Developers"] +description = "Bindings to Core Foundation for OS X" +homepage = "https://github.com/servo/core-foundation-rs" +license = "MIT / Apache-2.0" +repository = "https://github.com/servo/core-foundation-rs" +[dependencies.chrono] +version = "0.4" +optional = true + +[dependencies.core-foundation-sys] +version = "0.4.6" + +[dependencies.libc] +version = "0.2" + +[dependencies.uuid] +version = "0.5" +optional = true + +[features] +mac_os_10_7_support = ["core-foundation-sys/mac_os_10_7_support"] +mac_os_10_8_features = ["core-foundation-sys/mac_os_10_8_features"] +with-chrono = ["chrono"] +with-uuid = ["uuid"] diff --git a/core-foundation-0.4.6/src/array.rs b/core-foundation-0.4.6/src/array.rs new file mode 100644 index 000000000..e681c682f --- /dev/null +++ b/core-foundation-0.4.6/src/array.rs @@ -0,0 +1,235 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Heterogeneous immutable arrays. + +pub use core_foundation_sys::array::*; +pub use core_foundation_sys::base::{CFIndex, CFRelease}; +use core_foundation_sys::base::{CFTypeRef, kCFAllocatorDefault}; +use base::CFType; +use libc::c_void; +use std::mem; +use std::marker::PhantomData; + +use base::{CFIndexConvertible, TCFType, CFRange}; + +/// A heterogeneous immutable array. +pub struct CFArray(CFArrayRef, PhantomData); + +/// A trait describing how to convert from the stored *const c_void to the desired T +pub unsafe trait FromVoid { + unsafe fn from_void(x: *const c_void) -> Self; +} + +unsafe impl FromVoid for u32 { + unsafe fn from_void(x: *const c_void) -> u32 { + x as usize as u32 + } +} + +unsafe impl FromVoid for *const c_void { + unsafe fn from_void(x: *const c_void) -> *const c_void { + x + } +} + +unsafe impl FromVoid for CFType { + unsafe fn from_void(x: *const c_void) -> CFType { + TCFType::wrap_under_get_rule(mem::transmute(x)) + } +} + +impl Drop for CFArray { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +pub struct CFArrayIterator<'a, T: 'a> { + array: &'a CFArray, + index: CFIndex, +} + +impl<'a, T: FromVoid> Iterator for CFArrayIterator<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + if self.index >= self.array.len() { + None + } else { + let value = self.array.get(self.index); + self.index += 1; + Some(value) + } + } +} + +impl<'a, T: FromVoid> ExactSizeIterator for CFArrayIterator<'a, T> { + fn len(&self) -> usize { + (self.array.len() - self.index) as usize + } +} + +impl_TCFTypeGeneric!(CFArray, CFArrayRef, CFArrayGetTypeID); +impl_CFTypeDescriptionGeneric!(CFArray); + +impl CFArray { + /// Creates a new `CFArray` with the given elements, which must be `CFType` objects. + pub fn from_CFTypes(elems: &[T]) -> CFArray where T: TCFType { + unsafe { + let elems: Vec = elems.iter().map(|elem| elem.as_CFTypeRef()).collect(); + let array_ref = CFArrayCreate(kCFAllocatorDefault, + mem::transmute(elems.as_ptr()), + elems.len().to_CFIndex(), + &kCFTypeArrayCallBacks); + TCFType::wrap_under_create_rule(array_ref) + } + } + + #[deprecated(note = "please use `as_untyped` instead")] + pub fn to_untyped(self) -> CFArray { + unsafe { CFArray::wrap_under_get_rule(self.0) } + } + + pub fn as_untyped(&self) -> CFArray { + unsafe { CFArray::wrap_under_get_rule(self.0) } + } + + /// Iterates over the elements of this `CFArray`. + /// + /// Careful; the loop body must wrap the reference properly. Generally, when array elements are + /// Core Foundation objects (not always true), they need to be wrapped with + /// `TCFType::wrap_under_get_rule()`. + #[inline] + pub fn iter<'a>(&'a self) -> CFArrayIterator<'a, T> { + CFArrayIterator { + array: self, + index: 0 + } + } + + #[inline] + pub fn len(&self) -> CFIndex { + unsafe { + CFArrayGetCount(self.0) + } + } + + #[inline] + pub fn get(&self, index: CFIndex) -> T where T: FromVoid { + assert!(index < self.len()); + unsafe { T::from_void(CFArrayGetValueAtIndex(self.0, index)) } + } + + pub fn get_values(&self, range: CFRange) -> Vec<*const c_void> { + let mut vec = Vec::with_capacity(range.length as usize); + unsafe { + CFArrayGetValues(self.0, range, vec.as_mut_ptr()); + vec.set_len(range.length as usize); + vec + } + } + + pub fn get_all_values(&self) -> Vec<*const c_void> { + self.get_values(CFRange { + location: 0, + length: self.len() + }) + } +} + +impl<'a, T: FromVoid> IntoIterator for &'a CFArray { + type Item = T; + type IntoIter = CFArrayIterator<'a, T>; + + fn into_iter(self) -> CFArrayIterator<'a, T> { + self.iter() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::mem; + + #[test] + fn to_untyped_correct_retain_count() { + let array = CFArray::::from_CFTypes(&[]); + assert_eq!(array.retain_count(), 1); + + let untyped_array = array.to_untyped(); + assert_eq!(untyped_array.retain_count(), 1); + } + + #[test] + fn as_untyped_correct_retain_count() { + let array = CFArray::::from_CFTypes(&[]); + assert_eq!(array.retain_count(), 1); + + let untyped_array = array.as_untyped(); + assert_eq!(array.retain_count(), 2); + assert_eq!(untyped_array.retain_count(), 2); + + mem::drop(array); + assert_eq!(untyped_array.retain_count(), 1); + } + + #[test] + fn should_box_and_unbox() { + use number::CFNumber; + + let n0 = CFNumber::from(0); + let n1 = CFNumber::from(1); + let n2 = CFNumber::from(2); + let n3 = CFNumber::from(3); + let n4 = CFNumber::from(4); + let n5 = CFNumber::from(5); + + let arr = CFArray::from_CFTypes(&[ + n0.as_CFType(), + n1.as_CFType(), + n2.as_CFType(), + n3.as_CFType(), + n4.as_CFType(), + n5.as_CFType(), + ]); + + assert!(arr.get_all_values() == &[n0.as_CFTypeRef(), + n1.as_CFTypeRef(), + n2.as_CFTypeRef(), + n3.as_CFTypeRef(), + n4.as_CFTypeRef(), + n5.as_CFTypeRef()]); + + unsafe { + let mut sum = 0; + + let mut iter = arr.iter(); + assert_eq!(iter.len(), 6); + assert!(iter.next().is_some()); + assert_eq!(iter.len(), 5); + + for elem in iter { + let number: CFNumber = TCFType::wrap_under_get_rule(mem::transmute(elem)); + sum += number.to_i64().unwrap() + } + + assert!(sum == 15); + + for elem in arr.iter() { + let number: CFNumber = TCFType::wrap_under_get_rule(mem::transmute(elem)); + sum += number.to_i64().unwrap() + } + + assert!(sum == 30); + } + } +} diff --git a/core-foundation-0.4.6/src/base.rs b/core-foundation-0.4.6/src/base.rs new file mode 100644 index 000000000..3d945e976 --- /dev/null +++ b/core-foundation-0.4.6/src/base.rs @@ -0,0 +1,197 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::fmt; + +pub use core_foundation_sys::base::*; + +use string::CFString; + +pub trait CFIndexConvertible { + /// Always use this method to construct a `CFIndex` value. It performs bounds checking to + /// ensure the value is in range. + fn to_CFIndex(self) -> CFIndex; +} + +impl CFIndexConvertible for usize { + #[inline] + fn to_CFIndex(self) -> CFIndex { + let max_CFIndex = CFIndex::max_value(); + if self > (max_CFIndex as usize) { + panic!("value out of range") + } + self as CFIndex + } +} + +/// Superclass of all Core Foundation objects. +pub struct CFType(CFTypeRef); + +impl fmt::Debug for CFType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let desc = unsafe { + CFString::wrap_under_create_rule(CFCopyDescription(self.0)) + }; + desc.fmt(f) + } +} + +impl Clone for CFType { + #[inline] + fn clone(&self) -> CFType { + unsafe { + TCFType::wrap_under_get_rule(self.0) + } + } +} + +impl PartialEq for CFType { + #[inline] + fn eq(&self, other: &CFType) -> bool { + unsafe { + CFEqual(self.as_CFTypeRef(), other.as_CFTypeRef()) != 0 + } + } +} + +impl Drop for CFType { + fn drop(&mut self) { + unsafe { + CFRelease(self.0) + } + } +} + +/// An allocator for Core Foundation objects. +pub struct CFAllocator(CFAllocatorRef); + +impl Drop for CFAllocator { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFAllocator, CFAllocatorRef, CFAllocatorGetTypeID); + +impl CFAllocator { + #[inline] + pub fn new(mut context: CFAllocatorContext) -> CFAllocator { + unsafe { + let allocator_ref = CFAllocatorCreate(kCFAllocatorDefault, &mut context); + TCFType::wrap_under_create_rule(allocator_ref) + } + } +} + +/// All Core Foundation types implement this trait. The type parameter `TypeRef` specifies the +/// associated Core Foundation type: e.g. for `CFType` this is `CFTypeRef`; for `CFArray` this is +/// `CFArrayRef`. +pub trait TCFType { + /// Returns the object as its concrete TypeRef. + fn as_concrete_TypeRef(&self) -> ConcreteTypeRef; + + /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this + /// when following Core Foundation's "Create Rule". The reference count is *not* bumped. + unsafe fn wrap_under_create_rule(obj: ConcreteTypeRef) -> Self; + + /// Returns the type ID for this class. + fn type_id() -> CFTypeID; + + /// Returns the object as a wrapped `CFType`. The reference count is incremented by one. + #[inline] + fn as_CFType(&self) -> CFType { + unsafe { + TCFType::wrap_under_get_rule(self.as_CFTypeRef()) + } + } + + /// Returns the object as a raw `CFTypeRef`. The reference count is not adjusted. + fn as_CFTypeRef(&self) -> CFTypeRef; + + /// Returns an instance of the object, wrapping the underlying `CFTypeRef` subclass. Use this + /// when following Core Foundation's "Get Rule". The reference count *is* bumped. + unsafe fn wrap_under_get_rule(reference: ConcreteTypeRef) -> Self; + + /// Returns the reference count of the object. It is unwise to do anything other than test + /// whether the return value of this method is greater than zero. + #[inline] + fn retain_count(&self) -> CFIndex { + unsafe { + CFGetRetainCount(self.as_CFTypeRef()) + } + } + + /// Returns the type ID of this object. + #[inline] + fn type_of(&self) -> CFTypeID { + unsafe { + CFGetTypeID(self.as_CFTypeRef()) + } + } + + /// Writes a debugging version of this object on standard error. + fn show(&self) { + unsafe { + CFShow(self.as_CFTypeRef()) + } + } + + /// Returns true if this value is an instance of another type. + #[inline] + fn instance_of>(&self) -> bool { + self.type_of() == >::type_id() + } +} + +impl TCFType for CFType { + #[inline] + fn as_concrete_TypeRef(&self) -> CFTypeRef { + self.0 + } + + #[inline] + unsafe fn wrap_under_get_rule(reference: CFTypeRef) -> CFType { + let reference: CFTypeRef = CFRetain(reference); + TCFType::wrap_under_create_rule(reference) + } + + #[inline] + fn as_CFTypeRef(&self) -> CFTypeRef { + self.as_concrete_TypeRef() + } + + #[inline] + unsafe fn wrap_under_create_rule(obj: CFTypeRef) -> CFType { + CFType(obj) + } + + #[inline] + fn type_id() -> CFTypeID { + // FIXME(pcwalton): Is this right? + 0 + } +} + + +#[cfg(test)] +mod tests { + use super::*; + use boolean::CFBoolean; + + #[test] + fn cftype_instance_of() { + let string = CFString::from_static_string("foo"); + let cftype = string.as_CFType(); + + assert!(cftype.instance_of::<_, CFString>()); + assert!(!cftype.instance_of::<_, CFBoolean>()); + } +} diff --git a/core-foundation-0.4.6/src/boolean.rs b/core-foundation-0.4.6/src/boolean.rs new file mode 100644 index 000000000..e84346770 --- /dev/null +++ b/core-foundation-0.4.6/src/boolean.rs @@ -0,0 +1,77 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A Boolean type. + +use core_foundation_sys::base::{CFRelease}; +pub use core_foundation_sys::number::{CFBooleanRef, CFBooleanGetTypeID, kCFBooleanTrue, kCFBooleanFalse}; + +use base::TCFType; + +/// A Boolean type. +/// +/// FIXME(pcwalton): Should be a newtype struct, but that fails due to a Rust compiler bug. +pub struct CFBoolean(CFBooleanRef); + +impl Drop for CFBoolean { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFBoolean, CFBooleanRef, CFBooleanGetTypeID); +impl_CFTypeDescription!(CFBoolean); + +impl CFBoolean { + pub fn true_value() -> CFBoolean { + unsafe { + TCFType::wrap_under_get_rule(kCFBooleanTrue) + } + } + + pub fn false_value() -> CFBoolean { + unsafe { + TCFType::wrap_under_get_rule(kCFBooleanFalse) + } + } +} + +impl From for CFBoolean { + fn from(value: bool) -> CFBoolean { + if value { + CFBoolean::true_value() + } else { + CFBoolean::false_value() + } + } +} + +impl From for bool { + fn from(value: CFBoolean) -> bool { + value.0 == unsafe { kCFBooleanTrue } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn to_and_from_bool() { + let b_false = CFBoolean::from(false); + let b_true = CFBoolean::from(true); + assert_ne!(b_false, b_true); + assert_eq!(b_false, CFBoolean::false_value()); + assert_eq!(b_true, CFBoolean::true_value()); + assert!(!bool::from(b_false)); + assert!(bool::from(b_true)); + } +} diff --git a/core-foundation-0.4.6/src/bundle.rs b/core-foundation-0.4.6/src/bundle.rs new file mode 100644 index 000000000..4d75c302f --- /dev/null +++ b/core-foundation-0.4.6/src/bundle.rs @@ -0,0 +1,127 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Core Foundation Bundle Type + +pub use core_foundation_sys::bundle::*; +use core_foundation_sys::base::{CFRelease, kCFAllocatorDefault}; + +use base::TCFType; +use url::CFURL; +use dictionary::CFDictionary; + +/// A Bundle type. +pub struct CFBundle(CFBundleRef); + +impl Drop for CFBundle { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl CFBundle { + pub fn new(bundleURL: CFURL) -> Option { + unsafe { + let bundle_ref = CFBundleCreate(kCFAllocatorDefault, bundleURL.as_concrete_TypeRef()); + if bundle_ref.is_null() { + None + } else { + Some(TCFType::wrap_under_create_rule(bundle_ref)) + } + } + } + + pub fn main_bundle() -> CFBundle { + unsafe { + let bundle_ref = CFBundleGetMainBundle(); + TCFType::wrap_under_get_rule(bundle_ref) + } + } + + pub fn info_dictionary(&self) -> CFDictionary { + unsafe { + let info_dictionary = CFBundleGetInfoDictionary(self.0); + TCFType::wrap_under_get_rule(info_dictionary) + } + } + + pub fn executable_url(&self) -> Option { + unsafe { + let exe_url = CFBundleCopyExecutableURL(self.0); + if exe_url.is_null() { + None + } else { + Some(TCFType::wrap_under_create_rule(exe_url)) + } + } + } + + pub fn private_frameworks_url(&self) -> Option { + unsafe { + let fw_url = CFBundleCopyPrivateFrameworksURL(self.0); + if fw_url.is_null() { + None + } else { + Some(TCFType::wrap_under_create_rule(fw_url)) + } + } + } +} + +impl_TCFType!(CFBundle, CFBundleRef, CFBundleGetTypeID); + +#[test] +fn safari_executable_url() { + use string::CFString; + use url::{CFURL, kCFURLPOSIXPathStyle}; + + let cfstr_path = CFString::from_static_string("/Applications/Safari.app"); + let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); + let cfurl_executable = CFBundle::new(cfurl_path) + .expect("Safari not present") + .executable_url(); + assert!(cfurl_executable.is_some()); + assert_eq!(cfurl_executable + .unwrap() + .absolute() + .get_file_system_path(kCFURLPOSIXPathStyle) + .to_string(), + "/Applications/Safari.app/Contents/MacOS/Safari"); +} + +#[test] +fn safari_private_frameworks_url() { + use string::CFString; + use url::{CFURL, kCFURLPOSIXPathStyle}; + + let cfstr_path = CFString::from_static_string("/Applications/Safari.app"); + let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); + let cfurl_executable = CFBundle::new(cfurl_path) + .expect("Safari not present") + .private_frameworks_url(); + assert!(cfurl_executable.is_some()); + assert_eq!(cfurl_executable + .unwrap() + .absolute() + .get_file_system_path(kCFURLPOSIXPathStyle) + .to_string(), + "/Applications/Safari.app/Contents/Frameworks"); +} + +#[test] +fn non_existant_bundle() { + use string::CFString; + use url::{CFURL, kCFURLPOSIXPathStyle}; + + let cfstr_path = CFString::from_static_string("/usr/local/foo"); + let cfurl_path = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); + assert!(CFBundle::new(cfurl_path).is_none()); +} diff --git a/core-foundation-0.4.6/src/data.rs b/core-foundation-0.4.6/src/data.rs new file mode 100644 index 000000000..baa95f241 --- /dev/null +++ b/core-foundation-0.4.6/src/data.rs @@ -0,0 +1,69 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Core Foundation byte buffers. + +pub use core_foundation_sys::data::*; +use core_foundation_sys::base::{CFIndex, CFRelease}; +use core_foundation_sys::base::{kCFAllocatorDefault}; +use std::ops::Deref; +use std::slice; + +use base::{CFIndexConvertible, TCFType}; + +/// A byte buffer. +pub struct CFData(CFDataRef); + +impl Drop for CFData { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFData, CFDataRef, CFDataGetTypeID); +impl_CFTypeDescription!(CFData); + +impl CFData { + pub fn from_buffer(buffer: &[u8]) -> CFData { + unsafe { + let data_ref = CFDataCreate(kCFAllocatorDefault, + buffer.as_ptr(), + buffer.len().to_CFIndex()); + TCFType::wrap_under_create_rule(data_ref) + } + } + + /// Returns a pointer to the underlying bytes in this data. Note that this byte buffer is + /// read-only. + #[inline] + pub fn bytes<'a>(&'a self) -> &'a [u8] { + unsafe { + slice::from_raw_parts(CFDataGetBytePtr(self.0), self.len() as usize) + } + } + + /// Returns the length of this byte buffer. + #[inline] + pub fn len(&self) -> CFIndex { + unsafe { + CFDataGetLength(self.0) + } + } +} + +impl Deref for CFData { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.bytes() + } +} diff --git a/core-foundation-0.4.6/src/date.rs b/core-foundation-0.4.6/src/date.rs new file mode 100644 index 000000000..ee78cf81c --- /dev/null +++ b/core-foundation-0.4.6/src/date.rs @@ -0,0 +1,136 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Core Foundation date objects. + +pub use core_foundation_sys::date::*; +use core_foundation_sys::base::{CFRelease, kCFAllocatorDefault}; + +use base::TCFType; + +#[cfg(feature = "with-chrono")] +use chrono::NaiveDateTime; + +/// A date. +pub struct CFDate(CFDateRef); + +impl Drop for CFDate { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFDate, CFDateRef, CFDateGetTypeID); +impl_CFTypeDescription!(CFDate); +impl_CFComparison!(CFDate, CFDateCompare); + +impl CFDate { + #[inline] + pub fn new(time: CFAbsoluteTime) -> CFDate { + unsafe { + let date_ref = CFDateCreate(kCFAllocatorDefault, time); + TCFType::wrap_under_create_rule(date_ref) + } + } + + #[inline] + pub fn now() -> CFDate { + CFDate::new(unsafe { CFAbsoluteTimeGetCurrent() }) + } + + #[inline] + pub fn abs_time(&self) -> CFAbsoluteTime { + unsafe { + CFDateGetAbsoluteTime(self.0) + } + } + + #[cfg(feature = "with-chrono")] + pub fn naive_utc(&self) -> NaiveDateTime { + let ts = unsafe { + self.abs_time() + kCFAbsoluteTimeIntervalSince1970 + }; + let (secs, nanos) = if ts.is_sign_positive() { + (ts.trunc() as i64, ts.fract()) + } else { + // nanoseconds can't be negative in NaiveDateTime + (ts.trunc() as i64 - 1, 1.0 - ts.fract().abs()) + }; + NaiveDateTime::from_timestamp(secs, (nanos * 1e9).floor() as u32) + } + + #[cfg(feature = "with-chrono")] + pub fn from_naive_utc(time: NaiveDateTime) -> CFDate { + let secs = time.timestamp(); + let nanos = time.timestamp_subsec_nanos(); + let ts = unsafe { + secs as f64 + (nanos as f64 / 1e9) - kCFAbsoluteTimeIntervalSince1970 + }; + CFDate::new(ts) + } +} + +#[cfg(test)] +mod test { + use super::CFDate; + use std::cmp::Ordering; + + #[cfg(feature = "with-chrono")] + use chrono::NaiveDateTime; + + #[cfg(feature = "with-chrono")] + fn approx_eq(a: f64, b: f64) -> bool { + use std::f64; + + let same_sign = a.is_sign_positive() == b.is_sign_positive(); + let equal = ((a - b).abs() / f64::min(a.abs() + b.abs(), f64::MAX)) < f64::EPSILON; + (same_sign && equal) + } + + #[test] + fn date_comparison() { + let now = CFDate::now(); + let past = CFDate::new(now.abs_time() - 1.0); + assert_eq!(now.cmp(&past), Ordering::Greater); + assert_eq!(now.cmp(&now), Ordering::Equal); + assert_eq!(past.cmp(&now), Ordering::Less); + } + + #[test] + fn date_equality() { + let now = CFDate::now(); + let same_time = CFDate::new(now.abs_time()); + assert_eq!(now, same_time); + } + + #[test] + #[cfg(feature = "with-chrono")] + fn date_chrono_conversion_positive() { + let date = CFDate::now(); + let datetime = date.naive_utc(); + let converted = CFDate::from_naive_utc(datetime); + assert!(approx_eq(date.abs_time(), converted.abs_time())); + } + + #[test] + #[cfg(feature = "with-chrono")] + fn date_chrono_conversion_negative() { + use super::kCFAbsoluteTimeIntervalSince1970; + + let ts = unsafe { + kCFAbsoluteTimeIntervalSince1970 - 420.0 + }; + let date = CFDate::new(ts); + let datetime: NaiveDateTime = date.naive_utc(); + let converted = CFDate::from_naive_utc(datetime); + assert!(approx_eq(date.abs_time(), converted.abs_time())); + } +} diff --git a/core-foundation-0.4.6/src/dictionary.rs b/core-foundation-0.4.6/src/dictionary.rs new file mode 100644 index 000000000..822eb9cc4 --- /dev/null +++ b/core-foundation-0.4.6/src/dictionary.rs @@ -0,0 +1,133 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Dictionaries of key-value pairs. + +pub use core_foundation_sys::dictionary::*; +use core_foundation_sys::base::CFRelease; +use core_foundation_sys::base::{CFTypeRef, kCFAllocatorDefault}; +use libc::c_void; +use std::mem; +use std::ptr; + +use base::{CFType, CFIndexConvertible, TCFType}; + +/// An immutable dictionary of key-value pairs. +pub struct CFDictionary(CFDictionaryRef); + +impl Drop for CFDictionary { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFDictionary, CFDictionaryRef, CFDictionaryGetTypeID); +impl_CFTypeDescription!(CFDictionary); + +impl CFDictionary { + pub fn from_CFType_pairs(pairs: &[(K, V)]) -> CFDictionary + where K: TCFType, V: TCFType { + let (keys, values): (Vec,Vec) = + pairs.iter() + .map(|&(ref key, ref value)| (key.as_CFTypeRef(), value.as_CFTypeRef())) + .unzip(); + + unsafe { + let dictionary_ref = CFDictionaryCreate(kCFAllocatorDefault, + mem::transmute(keys.as_ptr()), + mem::transmute(values.as_ptr()), + keys.len().to_CFIndex(), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + TCFType::wrap_under_create_rule(dictionary_ref) + } + } + + #[inline] + pub fn len(&self) -> usize { + unsafe { + CFDictionaryGetCount(self.0) as usize + } + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[inline] + pub fn contains_key(&self, key: *const c_void) -> bool { + unsafe { + CFDictionaryContainsKey(self.0, key) != 0 + } + } + + /// Similar to `contains_key` but acts on a higher level, automatically converting from any + /// `TCFType` to the raw pointer of its concrete TypeRef. + #[inline] + pub fn contains_key2>(&self, key: &K) -> bool { + self.contains_key(key.as_concrete_TypeRef() as *const c_void) + } + + #[inline] + pub fn find(&self, key: *const c_void) -> Option<*const c_void> { + unsafe { + let mut value: *const c_void = ptr::null(); + if CFDictionaryGetValueIfPresent(self.0, key, &mut value) != 0 { + Some(value) + } else { + None + } + } + } + + /// Similar to `find` but acts on a higher level, automatically converting from any `TCFType` + /// to the raw pointer of its concrete TypeRef. + #[inline] + pub fn find2>(&self, key: &K) -> Option<*const c_void> { + self.find(key.as_concrete_TypeRef() as *const c_void) + } + + /// # Panics + /// + /// Panics if the key is not present in the dictionary. Use `find` to get an `Option` instead + /// of panicking. + #[inline] + pub fn get(&self, key: *const c_void) -> *const c_void { + self.find(key).expect(&format!("No entry found for key {:p}", key)) + } + + /// A convenience function to retrieve `CFType` instances. + #[inline] + pub unsafe fn get_CFType(&self, key: *const c_void) -> CFType { + let value: CFTypeRef = mem::transmute(self.get(key)); + TCFType::wrap_under_get_rule(value) + } + + #[inline] + pub unsafe fn set_value(&self, key: *const c_void, value: *const c_void) { + CFDictionarySetValue(self.0, key, value) + } + + pub fn get_keys_and_values(&self) -> (Vec<*const c_void>, Vec<*const c_void>) { + let length = self.len(); + let mut keys = Vec::with_capacity(length); + let mut values = Vec::with_capacity(length); + + unsafe { + CFDictionaryGetKeysAndValues(self.0, keys.as_mut_ptr(), values.as_mut_ptr()); + keys.set_len(length); + values.set_len(length); + } + + (keys, values) + } +} diff --git a/core-foundation-0.4.6/src/error.rs b/core-foundation-0.4.6/src/error.rs new file mode 100644 index 000000000..af9b26f4e --- /dev/null +++ b/core-foundation-0.4.6/src/error.rs @@ -0,0 +1,77 @@ +// Copyright 2016 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Core Foundation errors. + +use core_foundation_sys::error::*; +use core_foundation_sys::base::CFRelease; +use std::error::Error; +use std::fmt; + +use base::{CFIndex, TCFType}; +use string::CFString; + +/// An error value. +pub struct CFError(CFErrorRef); + +impl Drop for CFError { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFError, CFErrorRef, CFErrorGetTypeID); + +impl fmt::Debug for CFError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("CFError") + .field("domain", &self.domain()) + .field("code", &self.code()) + .field("description", &self.description()) + .finish() + } +} + +impl fmt::Display for CFError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}", self.description()) + } +} + +impl Error for CFError { + fn description(&self) -> &str { + "a Core Foundation error" + } +} + +impl CFError { + /// Returns a string identifying the domain with which this error is + /// associated. + pub fn domain(&self) -> CFString { + unsafe { + let s = CFErrorGetDomain(self.0); + CFString::wrap_under_get_rule(s) + } + } + + /// Returns the code identifying this type of error. + pub fn code(&self) -> CFIndex { + unsafe { CFErrorGetCode(self.0) } + } + + /// Returns a human-presentable description of the error. + pub fn description(&self) -> CFString { + unsafe { + let s = CFErrorCopyDescription(self.0); + CFString::wrap_under_create_rule(s) + } + } +} diff --git a/core-foundation-0.4.6/src/lib.rs b/core-foundation-0.4.6/src/lib.rs new file mode 100644 index 000000000..775cd23ac --- /dev/null +++ b/core-foundation-0.4.6/src/lib.rs @@ -0,0 +1,222 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![allow(non_snake_case)] + +extern crate core_foundation_sys; +extern crate libc; + +#[cfg(feature = "with-chrono")] +extern crate chrono; + +#[macro_export] +macro_rules! impl_TCFType { + ($ty:ident, $raw:ident, $ty_id:ident) => { + impl $crate::base::TCFType<$raw> for $ty { + #[inline] + fn as_concrete_TypeRef(&self) -> $raw { + self.0 + } + + #[inline] + unsafe fn wrap_under_get_rule(reference: $raw) -> $ty { + let reference = ::std::mem::transmute(::core_foundation_sys::base::CFRetain(::std::mem::transmute(reference))); + $crate::base::TCFType::wrap_under_create_rule(reference) + } + + #[inline] + fn as_CFTypeRef(&self) -> ::core_foundation_sys::base::CFTypeRef { + unsafe { + ::std::mem::transmute(self.as_concrete_TypeRef()) + } + } + + #[inline] + unsafe fn wrap_under_create_rule(obj: $raw) -> $ty { + $ty(obj) + } + + #[inline] + fn type_id() -> ::core_foundation_sys::base::CFTypeID { + unsafe { + $ty_id() + } + } + } + + impl Clone for $ty { + #[inline] + fn clone(&self) -> $ty { + unsafe { + $ty::wrap_under_get_rule(self.0) + } + } + } + + impl PartialEq for $ty { + #[inline] + fn eq(&self, other: &$ty) -> bool { + self.as_CFType().eq(&other.as_CFType()) + } + } + + impl Eq for $ty { } + } +} + +// This is basically identical to the implementation above. I can't +// think of a clean way to have them share code +#[macro_export] +macro_rules! impl_TCFTypeGeneric { + ($ty:ident, $raw:ident, $ty_id:ident) => { + impl $crate::base::TCFType<$raw> for $ty { + #[inline] + fn as_concrete_TypeRef(&self) -> $raw { + self.0 + } + + #[inline] + unsafe fn wrap_under_get_rule(reference: $raw) -> $ty { + let reference = ::std::mem::transmute(::core_foundation_sys::base::CFRetain(::std::mem::transmute(reference))); + $crate::base::TCFType::wrap_under_create_rule(reference) + } + + #[inline] + fn as_CFTypeRef(&self) -> ::core_foundation_sys::base::CFTypeRef { + unsafe { + ::std::mem::transmute(self.as_concrete_TypeRef()) + } + } + + #[inline] + unsafe fn wrap_under_create_rule(obj: $raw) -> $ty { + $ty(obj, PhantomData) + } + + #[inline] + fn type_id() -> ::core_foundation_sys::base::CFTypeID { + unsafe { + $ty_id() + } + } + } + + impl Clone for $ty { + #[inline] + fn clone(&self) -> $ty { + unsafe { + $ty::wrap_under_get_rule(self.0) + } + } + } + + impl PartialEq for $ty { + #[inline] + fn eq(&self, other: &$ty) -> bool { + self.as_CFType().eq(&other.as_CFType()) + } + } + + impl Eq for $ty { } + } +} + +#[macro_export] +macro_rules! impl_CFTypeDescription { + ($ty:ident) => { + impl ::std::fmt::Debug for $ty { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + self.as_CFType().fmt(f) + } + } + } +} + +// The same as impl_CFTypeDescription but with a type parameter +#[macro_export] +macro_rules! impl_CFTypeDescriptionGeneric { + ($ty:ident) => { + impl ::std::fmt::Debug for $ty { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + self.as_CFType().fmt(f) + } + } + } +} + +#[macro_export] +macro_rules! impl_CFComparison { + ($ty:ident, $compare:ident) => { + impl PartialOrd for $ty { + #[inline] + fn partial_cmp(&self, other: &$ty) -> Option<::std::cmp::Ordering> { + unsafe { + Some($compare(self.as_concrete_TypeRef(), other.as_concrete_TypeRef(), ::std::ptr::null_mut()).into()) + } + } + } + + impl Ord for $ty { + #[inline] + fn cmp(&self, other: &$ty) -> ::std::cmp::Ordering { + self.partial_cmp(other).unwrap() + } + } + } +} + +pub mod array; +pub mod base; +pub mod boolean; +pub mod data; +pub mod date; +pub mod dictionary; +pub mod error; +pub mod number; +pub mod set; +pub mod string; +pub mod url; +pub mod bundle; +pub mod propertylist; +pub mod runloop; +pub mod timezone; +pub mod uuid; + +#[cfg(test)] +pub mod test { + #[test] + fn test_stuff() { + use base::TCFType; + use boolean::CFBoolean; + use number::CFNumber; + use dictionary::CFDictionary; + use string::CFString; + + /*let n = CFNumber::new_number(42 as i32); + io::println(format!("%d", (&n).retain_count() as int)); + (&n).show();*/ + + let bar = CFString::from_static_string("Bar"); + let baz = CFString::from_static_string("Baz"); + let boo = CFString::from_static_string("Boo"); + let foo = CFString::from_static_string("Foo"); + let tru = CFBoolean::true_value(); + let n42 = CFNumber::from(42); + + let d = CFDictionary::from_CFType_pairs(&[ + (bar.as_CFType(), boo.as_CFType()), + (baz.as_CFType(), tru.as_CFType()), + (foo.as_CFType(), n42.as_CFType()), + ]); + + let (v1, v2) = d.get_keys_and_values(); + + assert!(v1 == &[bar.as_CFTypeRef(), baz.as_CFTypeRef(), foo.as_CFTypeRef()]); + assert!(v2 == &[boo.as_CFTypeRef(), tru.as_CFTypeRef(), n42.as_CFTypeRef()]); + } +} diff --git a/core-foundation-0.4.6/src/number.rs b/core-foundation-0.4.6/src/number.rs new file mode 100644 index 000000000..cd02635fe --- /dev/null +++ b/core-foundation-0.4.6/src/number.rs @@ -0,0 +1,146 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Immutable numbers. + +use core_foundation_sys::base::{CFRelease, kCFAllocatorDefault}; +pub use core_foundation_sys::number::*; +use std::mem; + +use base::{TCFType}; + +/// An immutable numeric value. +pub struct CFNumber(CFNumberRef); + +impl Drop for CFNumber { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFNumber, CFNumberRef, CFNumberGetTypeID); +impl_CFTypeDescription!(CFNumber); +impl_CFComparison!(CFNumber, CFNumberCompare); + +impl CFNumber { + #[inline] + pub fn to_i64(&self) -> Option { + unsafe { + let mut value: i64 = 0; + let ok = CFNumberGetValue(self.0, kCFNumberSInt64Type, mem::transmute(&mut value)); + if ok { Some(value) } else { None } + } + } + + #[inline] + pub fn to_f32(&self) -> Option { + unsafe { + let mut value: f32 = 0.0; + let ok = CFNumberGetValue(self.0, kCFNumberFloat32Type, mem::transmute(&mut value)); + if ok { Some(value) } else { None } + } + } + + #[inline] + pub fn to_f64(&self) -> Option { + unsafe { + let mut value: f64 = 0.0; + let ok = CFNumberGetValue(self.0, kCFNumberFloat64Type, mem::transmute(&mut value)); + if ok { Some(value) } else { None } + } + } + + #[deprecated(note = "please use `CFNumber::from` instead")] + #[inline] + pub fn from_i32(value: i32) -> CFNumber { + CFNumber::from(value) + } + + #[deprecated(note = "please use `CFNumber::from` instead")] + #[inline] + pub fn from_i64(value: i64) -> CFNumber { + Self::from(value) + } + + #[deprecated(note = "please use `CFNumber::from` instead")] + #[inline] + pub fn from_f32(value: f32) -> CFNumber { + Self::from(value) + } + + #[deprecated(note = "please use `CFNumber::from` instead")] + #[inline] + pub fn from_f64(value: f64) -> CFNumber { + Self::from(value) + } +} + +impl From for CFNumber { + #[inline] + fn from(value: i32) -> Self { + unsafe { + let number_ref = CFNumberCreate( + kCFAllocatorDefault, + kCFNumberSInt32Type, + mem::transmute(&value), + ); + TCFType::wrap_under_create_rule(number_ref) + } + } +} + +impl From for CFNumber { + #[inline] + fn from(value: i64) -> Self { + unsafe { + let number_ref = CFNumberCreate( + kCFAllocatorDefault, + kCFNumberSInt64Type, + mem::transmute(&value), + ); + TCFType::wrap_under_create_rule(number_ref) + } + } +} + +impl From for CFNumber { + #[inline] + fn from(value: f32) -> Self { + unsafe { + let number_ref = CFNumberCreate( + kCFAllocatorDefault, + kCFNumberFloat32Type, + mem::transmute(&value), + ); + TCFType::wrap_under_create_rule(number_ref) + } + } +} + +impl From for CFNumber { + #[inline] + fn from(value: f64) -> Self { + unsafe { + let number_ref = CFNumberCreate( + kCFAllocatorDefault, + kCFNumberFloat64Type, + mem::transmute(&value), + ); + TCFType::wrap_under_create_rule(number_ref) + } + } +} + +/// A convenience function to create CFNumbers. +#[deprecated(note = "please use `CFNumber::from` instead")] +pub fn number(value: i64) -> CFNumber { + CFNumber::from(value) +} diff --git a/core-foundation-0.4.6/src/propertylist.rs b/core-foundation-0.4.6/src/propertylist.rs new file mode 100644 index 000000000..b8d5e020e --- /dev/null +++ b/core-foundation-0.4.6/src/propertylist.rs @@ -0,0 +1,255 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Core Foundation property lists + +use std::ptr; +use std::mem; + +use libc::c_void; + +use error::CFError; +use data::CFData; +use base::{CFType, TCFType}; + +pub use core_foundation_sys::propertylist::*; +use core_foundation_sys::error::CFErrorRef; +use core_foundation_sys::base::{CFGetRetainCount, CFGetTypeID, CFIndex, CFRelease, CFRetain, + CFShow, CFTypeID, kCFAllocatorDefault}; + +pub fn create_with_data(data: CFData, + options: CFPropertyListMutabilityOptions) + -> Result<(*const c_void, CFPropertyListFormat), CFError> { + unsafe { + let mut error: CFErrorRef = ptr::null_mut(); + let mut format: CFPropertyListFormat = 0; + let property_list = CFPropertyListCreateWithData(kCFAllocatorDefault, + data.as_concrete_TypeRef(), + options, + &mut format, + &mut error); + if property_list.is_null() { + Err(TCFType::wrap_under_create_rule(error)) + } else { + Ok((property_list, format)) + } + } +} + +pub fn create_data(property_list: *const c_void, format: CFPropertyListFormat) -> Result { + unsafe { + let mut error: CFErrorRef = ptr::null_mut(); + let data_ref = CFPropertyListCreateData(kCFAllocatorDefault, + property_list, + format, + 0, + &mut error); + if data_ref.is_null() { + Err(TCFType::wrap_under_create_rule(error)) + } else { + Ok(TCFType::wrap_under_create_rule(data_ref)) + } + } +} + + +/// Trait for all subclasses of [`CFPropertyList`]. +/// +/// [`CFPropertyList`]: struct.CFPropertyList.html +pub trait CFPropertyListSubClass: TCFType<*const Raw> { + /// Create an instance of the superclass type [`CFPropertyList`] for this instance. + /// + /// [`CFPropertyList`]: struct.CFPropertyList.html + fn to_CFPropertyList(&self) -> CFPropertyList { + unsafe { CFPropertyList::wrap_under_get_rule(self.as_concrete_TypeRef() as *const c_void) } + } +} + +impl CFPropertyListSubClass<::data::__CFData> for ::data::CFData {} +impl CFPropertyListSubClass<::string::__CFString> for ::string::CFString {} +impl CFPropertyListSubClass<::array::__CFArray> for ::array::CFArray {} +impl CFPropertyListSubClass<::dictionary::__CFDictionary> for ::dictionary::CFDictionary {} +impl CFPropertyListSubClass<::date::__CFDate> for ::date::CFDate {} +impl CFPropertyListSubClass<::number::__CFBoolean> for ::boolean::CFBoolean {} +impl CFPropertyListSubClass<::number::__CFNumber> for ::number::CFNumber {} + +/// A CFPropertyList struct. This is superclass to [`CFData`], [`CFString`], [`CFArray`], +/// [`CFDictionary`], [`CFDate`], [`CFBoolean`], and [`CFNumber`]. +/// +/// This superclass type does not have its own `CFTypeID`, instead each instance has the `CFTypeID` +/// of the subclass it is an instance of. Thus, this type cannot implement the [`TCFType`] trait, +/// since it cannot implement the static [`TCFType::type_id()`] method. +/// +/// [`CFData`]: ../data/struct.CFData.html +/// [`CFString`]: ../string/struct.CFString.html +/// [`CFArray`]: ../array/struct.CFArray.html +/// [`CFDictionary`]: ../dictionary/struct.CFDictionary.html +/// [`CFDate`]: ../date/struct.CFDate.html +/// [`CFBoolean`]: ../boolean/struct.CFBoolean.html +/// [`CFNumber`]: ../number/struct.CFNumber.html +/// [`TCFType`]: ../base/trait.TCFType.html +/// [`TCFType::type_id()`]: ../base/trait.TCFType.html#method.type_of +pub struct CFPropertyList(CFPropertyListRef); + +impl Drop for CFPropertyList { + fn drop(&mut self) { + unsafe { CFRelease(self.as_CFTypeRef()) } + } +} + +impl CFPropertyList { + #[inline] + pub fn as_concrete_TypeRef(&self) -> CFPropertyListRef { + self.0 + } + + #[inline] + pub unsafe fn wrap_under_get_rule(reference: CFPropertyListRef) -> CFPropertyList { + let reference = mem::transmute(CFRetain(mem::transmute(reference))); + CFPropertyList(reference) + } + + #[inline] + pub fn as_CFType(&self) -> CFType { + unsafe { CFType::wrap_under_get_rule(self.as_CFTypeRef()) } + } + + #[inline] + pub fn as_CFTypeRef(&self) -> ::core_foundation_sys::base::CFTypeRef { + unsafe { mem::transmute(self.as_concrete_TypeRef()) } + } + + #[inline] + pub unsafe fn wrap_under_create_rule(obj: CFPropertyListRef) -> CFPropertyList { + CFPropertyList(obj) + } + + /// Returns the reference count of the object. It is unwise to do anything other than test + /// whether the return value of this method is greater than zero. + #[inline] + pub fn retain_count(&self) -> CFIndex { + unsafe { CFGetRetainCount(self.as_CFTypeRef()) } + } + + /// Returns the type ID of this object. Will be one of CFData, CFString, CFArray, CFDictionary, + /// CFDate, CFBoolean, or CFNumber. + #[inline] + pub fn type_of(&self) -> CFTypeID { + unsafe { CFGetTypeID(self.as_CFTypeRef()) } + } + + /// Writes a debugging version of this object on standard error. + pub fn show(&self) { + unsafe { CFShow(self.as_CFTypeRef()) } + } + + /// Returns true if this value is an instance of another type. + #[inline] + pub fn instance_of>( + &self, + ) -> bool { + self.type_of() == >::type_id() + } +} + +impl Clone for CFPropertyList { + #[inline] + fn clone(&self) -> CFPropertyList { + unsafe { CFPropertyList::wrap_under_get_rule(self.0) } + } +} + +impl PartialEq for CFPropertyList { + #[inline] + fn eq(&self, other: &CFPropertyList) -> bool { + self.as_CFType().eq(&other.as_CFType()) + } +} + +impl Eq for CFPropertyList {} + +impl CFPropertyList { + /// Try to downcast the [`CFPropertyList`] to a subclass. Checking if the instance is the correct + /// subclass happens at runtime and an error is returned if it is not the correct type. + /// Works similar to [`Box::downcast`]. + /// + /// # Examples + /// + /// ``` + /// # use core_foundation::string::CFString; + /// # use core_foundation::propertylist::{CFPropertyList, CFPropertyListSubClass}; + /// # + /// // Create a string. + /// let string: CFString = CFString::from_static_string("FooBar"); + /// // Cast it up to a property list. + /// let propertylist: CFPropertyList = string.to_CFPropertyList(); + /// // Cast it down again. + /// assert!(propertylist.downcast::<_, CFString>().unwrap().to_string() == "FooBar"); + /// ``` + /// + /// [`CFPropertyList`]: struct.CFPropertyList.html + /// [`Box::downcast`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast + pub fn downcast>(&self) -> Option { + if self.instance_of::<_, T>() { + Some(unsafe { T::wrap_under_get_rule(self.0 as *const Raw) }) + } else { + None + } + } +} + + + +#[cfg(test)] +pub mod test { + use super::*; + use string::CFString; + use boolean::CFBoolean; + + #[test] + fn test_property_list_serialization() { + use base::{TCFType, CFEqual}; + use boolean::CFBoolean; + use number::CFNumber; + use dictionary::CFDictionary; + use string::CFString; + use super::*; + + let bar = CFString::from_static_string("Bar"); + let baz = CFString::from_static_string("Baz"); + let boo = CFString::from_static_string("Boo"); + let foo = CFString::from_static_string("Foo"); + let tru = CFBoolean::true_value(); + let n42 = CFNumber::from(42); + + let dict1 = CFDictionary::from_CFType_pairs(&[(bar.as_CFType(), boo.as_CFType()), + (baz.as_CFType(), tru.as_CFType()), + (foo.as_CFType(), n42.as_CFType())]); + + let data = create_data(dict1.as_CFTypeRef(), kCFPropertyListXMLFormat_v1_0).unwrap(); + let (dict2, _) = create_with_data(data, kCFPropertyListImmutable).unwrap(); + unsafe { + assert!(CFEqual(dict1.as_CFTypeRef(), dict2) == 1); + } + } + + #[test] + fn downcast_string() { + let propertylist = CFString::from_static_string("Bar").to_CFPropertyList(); + assert!(propertylist.downcast::<_, CFString>().unwrap().to_string() == "Bar"); + assert!(propertylist.downcast::<_, CFBoolean>().is_none()); + } + + #[test] + fn downcast_boolean() { + let propertylist = CFBoolean::true_value().to_CFPropertyList(); + assert!(propertylist.downcast::<_, CFBoolean>().is_some()); + assert!(propertylist.downcast::<_, CFString>().is_none()); + } +} diff --git a/core-foundation-0.4.6/src/runloop.rs b/core-foundation-0.4.6/src/runloop.rs new file mode 100644 index 000000000..fa2de8021 --- /dev/null +++ b/core-foundation-0.4.6/src/runloop.rs @@ -0,0 +1,212 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_upper_case_globals)] + +pub use core_foundation_sys::runloop::*; +use core_foundation_sys::base::{CFIndex, CFRelease}; +use core_foundation_sys::base::{kCFAllocatorDefault, CFOptionFlags}; +use core_foundation_sys::string::CFStringRef; + +use base::{TCFType}; +use date::{CFAbsoluteTime, CFTimeInterval}; +use string::{CFString}; + +pub type CFRunLoopMode = CFStringRef; + +pub struct CFRunLoop(CFRunLoopRef); + +impl Drop for CFRunLoop { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFRunLoop, CFRunLoopRef, CFRunLoopGetTypeID); +impl_CFTypeDescription!(CFRunLoop); + +impl CFRunLoop { + pub fn get_current() -> CFRunLoop { + unsafe { + let run_loop_ref = CFRunLoopGetCurrent(); + TCFType::wrap_under_get_rule(run_loop_ref) + } + } + + pub fn get_main() -> CFRunLoop { + unsafe { + let run_loop_ref = CFRunLoopGetMain(); + TCFType::wrap_under_get_rule(run_loop_ref) + } + } + + pub fn run_current() { + unsafe { + CFRunLoopRun(); + } + } + + pub fn stop(&self) { + unsafe { + CFRunLoopStop(self.0); + } + } + + pub fn current_mode(&self) -> Option { + unsafe { + let string_ref = CFRunLoopCopyCurrentMode(self.0); + if string_ref.is_null() { + return None; + } + + let cf_string: CFString = TCFType::wrap_under_create_rule(string_ref); + Some(cf_string.to_string()) + } + } + + pub fn contains_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) -> bool { + unsafe { + CFRunLoopContainsTimer(self.0, timer.0, mode) != 0 + } + } + + pub fn add_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) { + unsafe { + CFRunLoopAddTimer(self.0, timer.0, mode); + } + } + + pub fn remove_timer(&self, timer: &CFRunLoopTimer, mode: CFRunLoopMode) { + unsafe { + CFRunLoopRemoveTimer(self.0, timer.0, mode); + } + } + + pub fn contains_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) -> bool { + unsafe { + CFRunLoopContainsSource(self.0, source.0, mode) != 0 + } + } + + pub fn add_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) { + unsafe { + CFRunLoopAddSource(self.0, source.0, mode); + } + } + + pub fn remove_source(&self, source: &CFRunLoopSource, mode: CFRunLoopMode) { + unsafe { + CFRunLoopRemoveSource(self.0, source.0, mode); + } + } + + pub fn contains_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) -> bool { + unsafe { + CFRunLoopContainsObserver(self.0, observer.0, mode) != 0 + } + } + + pub fn add_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) { + unsafe { + CFRunLoopAddObserver(self.0, observer.0, mode); + } + } + + pub fn remove_observer(&self, observer: &CFRunLoopObserver, mode: CFRunLoopMode) { + unsafe { + CFRunLoopRemoveObserver(self.0, observer.0, mode); + } + } + +} + +pub struct CFRunLoopTimer(CFRunLoopTimerRef); + +impl Drop for CFRunLoopTimer { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFRunLoopTimer, CFRunLoopTimerRef, CFRunLoopTimerGetTypeID); + +impl CFRunLoopTimer { + pub fn new(fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimer { + unsafe { + let timer_ref = CFRunLoopTimerCreate(kCFAllocatorDefault, fireDate, interval, flags, order, callout, context); + TCFType::wrap_under_create_rule(timer_ref) + } + } +} + + +pub struct CFRunLoopSource(CFRunLoopSourceRef); + +impl Drop for CFRunLoopSource { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFRunLoopSource, CFRunLoopSourceRef, CFRunLoopSourceGetTypeID); + + +pub struct CFRunLoopObserver(CFRunLoopObserverRef); + +impl Drop for CFRunLoopObserver { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFRunLoopObserver, CFRunLoopObserverRef, CFRunLoopObserverGetTypeID); + +#[cfg(test)] +mod test { + use super::*; + use date::{CFDate, CFAbsoluteTime}; + use std::mem; + use libc::c_void; + + #[test] + fn wait_200_milliseconds() { + let run_loop = CFRunLoop::get_current(); + let mut now = CFDate::now().abs_time(); + let mut context = unsafe { CFRunLoopTimerContext { + version: 0, + info: mem::transmute(&mut now), + retain: mem::zeroed(), + release: mem::zeroed(), + copyDescription: mem::zeroed(), + } }; + + + let run_loop_timer = CFRunLoopTimer::new(now + 0.20f64, 0f64, 0, 0, timer_popped, &mut context); + unsafe { + run_loop.add_timer(&run_loop_timer, kCFRunLoopDefaultMode); + } + CFRunLoop::run_current(); + } + + extern "C" fn timer_popped(_timer: CFRunLoopTimerRef, info: *mut c_void) { + let previous_now_ptr: *const CFAbsoluteTime = unsafe { mem::transmute(info) }; + let previous_now = unsafe { *previous_now_ptr }; + let now = CFDate::now().abs_time(); + assert!(now - previous_now > 0.19 && now - previous_now < 0.21); + CFRunLoop::get_current().stop(); + } +} diff --git a/core-foundation-0.4.6/src/set.rs b/core-foundation-0.4.6/src/set.rs new file mode 100644 index 000000000..4dab26f55 --- /dev/null +++ b/core-foundation-0.4.6/src/set.rs @@ -0,0 +1,46 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! An immutable bag of elements. + +pub use core_foundation_sys::set::*; +use core_foundation_sys::base::CFRelease; +use core_foundation_sys::base::{CFTypeRef, kCFAllocatorDefault}; + +use base::{CFIndexConvertible, TCFType}; + +use std::mem; + +/// An immutable bag of elements. +pub struct CFSet(CFSetRef); + +impl Drop for CFSet { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFSet, CFSetRef, CFSetGetTypeID); +impl_CFTypeDescription!(CFSet); + +impl CFSet { + /// Creates a new set from a list of `CFType` instances. + pub fn from_slice(elems: &[T]) -> CFSet where T: TCFType { + unsafe { + let elems: Vec = elems.iter().map(|elem| elem.as_CFTypeRef()).collect(); + let set_ref = CFSetCreate(kCFAllocatorDefault, + mem::transmute(elems.as_ptr()), + elems.len().to_CFIndex(), + &kCFTypeSetCallBacks); + TCFType::wrap_under_create_rule(set_ref) + } + } +} diff --git a/core-foundation-0.4.6/src/string.rs b/core-foundation-0.4.6/src/string.rs new file mode 100644 index 000000000..5026b71ae --- /dev/null +++ b/core-foundation-0.4.6/src/string.rs @@ -0,0 +1,149 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Immutable strings. + +pub use core_foundation_sys::string::*; + +use base::{CFIndexConvertible, TCFType}; + +use core_foundation_sys::base::{Boolean, CFIndex, CFRange, CFRelease}; +use core_foundation_sys::base::{kCFAllocatorDefault, kCFAllocatorNull}; +use std::fmt; +use std::str::{self, FromStr}; +use std::ptr; +use std::ffi::CStr; + +/// An immutable string in one of a variety of encodings. +pub struct CFString(CFStringRef); + +impl Drop for CFString { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFString, CFStringRef, CFStringGetTypeID); + +impl FromStr for CFString { + type Err = (); + + /// See also CFString::new for a variant of this which does not return a Result + #[inline] + fn from_str(string: &str) -> Result { + Ok(CFString::new(string)) + } +} + +impl<'a> From<&'a str> for CFString { + #[inline] + fn from(string: &'a str) -> CFString { + CFString::new(string) + } +} + +impl fmt::Display for CFString { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + unsafe { + // Do this without allocating if we can get away with it + let c_string = CFStringGetCStringPtr(self.0, kCFStringEncodingUTF8); + if c_string != ptr::null() { + let c_str = CStr::from_ptr(c_string); + fmt.write_str(str::from_utf8_unchecked(c_str.to_bytes())) + } else { + let char_len = self.char_len(); + + // First, ask how big the buffer ought to be. + let mut bytes_required: CFIndex = 0; + CFStringGetBytes(self.0, + CFRange { location: 0, length: char_len }, + kCFStringEncodingUTF8, + 0, + false as Boolean, + ptr::null_mut(), + 0, + &mut bytes_required); + + // Then, allocate the buffer and actually copy. + let mut buffer = vec![b'\x00'; bytes_required as usize]; + + let mut bytes_used: CFIndex = 0; + let chars_written = CFStringGetBytes(self.0, + CFRange { location: 0, length: char_len }, + kCFStringEncodingUTF8, + 0, + false as Boolean, + buffer.as_mut_ptr(), + buffer.len().to_CFIndex(), + &mut bytes_used) as usize; + assert!(chars_written.to_CFIndex() == char_len); + + // This is dangerous; we over-allocate and null-terminate the string (during + // initialization). + assert!(bytes_used == buffer.len().to_CFIndex()); + fmt.write_str(str::from_utf8_unchecked(&buffer)) + } + } + } +} + +impl fmt::Debug for CFString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "\"{}\"", self) + } +} + + +impl CFString { + /// Creates a new `CFString` instance from a Rust string. + #[inline] + pub fn new(string: &str) -> CFString { + unsafe { + let string_ref = CFStringCreateWithBytes(kCFAllocatorDefault, + string.as_ptr(), + string.len().to_CFIndex(), + kCFStringEncodingUTF8, + false as Boolean); + CFString::wrap_under_create_rule(string_ref) + } + } + + /// Like `CFString::new`, but references a string that can be used as a backing store + /// by virtue of being statically allocated. + #[inline] + pub fn from_static_string(string: &'static str) -> CFString { + unsafe { + let string_ref = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, + string.as_ptr(), + string.len().to_CFIndex(), + kCFStringEncodingUTF8, + false as Boolean, + kCFAllocatorNull); + TCFType::wrap_under_create_rule(string_ref) + } + } + + /// Returns the number of characters in the string. + #[inline] + pub fn char_len(&self) -> CFIndex { + unsafe { + CFStringGetLength(self.0) + } + } +} + +#[test] +fn string_and_back() { + let original = "The quick brown fox jumped over the slow lazy dog."; + let cfstr = CFString::from_static_string(original); + let converted = cfstr.to_string(); + assert!(converted == original); +} diff --git a/core-foundation-0.4.6/src/timezone.rs b/core-foundation-0.4.6/src/timezone.rs new file mode 100644 index 000000000..5e2650d04 --- /dev/null +++ b/core-foundation-0.4.6/src/timezone.rs @@ -0,0 +1,101 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Core Foundation time zone objects. + +pub use core_foundation_sys::timezone::*; +use core_foundation_sys::base::{CFRelease, kCFAllocatorDefault}; + +use base::TCFType; +use date::{CFDate, CFTimeInterval}; + +#[cfg(feature = "with-chrono")] +use chrono::{FixedOffset, NaiveDateTime}; + +/// A time zone. +pub struct CFTimeZone(CFTimeZoneRef); + +impl Drop for CFTimeZone { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFTimeZone, CFTimeZoneRef, CFTimeZoneGetTypeID); +impl_CFTypeDescription!(CFTimeZone); + +impl Default for CFTimeZone { + fn default() -> CFTimeZone { + unsafe { + let tz_ref = CFTimeZoneCopyDefault(); + TCFType::wrap_under_create_rule(tz_ref) + } + } +} + +impl CFTimeZone { + #[inline] + pub fn new(interval: CFTimeInterval) -> CFTimeZone { + unsafe { + let tz_ref = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, interval); + TCFType::wrap_under_create_rule(tz_ref) + } + } + + #[inline] + pub fn system() -> CFTimeZone { + unsafe { + let tz_ref = CFTimeZoneCopySystem(); + TCFType::wrap_under_create_rule(tz_ref) + } + } + + pub fn seconds_from_gmt(&self, date: CFDate) -> CFTimeInterval { + unsafe { + CFTimeZoneGetSecondsFromGMT(self.0, date.abs_time()) + } + } + + #[cfg(feature = "with-chrono")] + pub fn offset_at_date(&self, date: NaiveDateTime) -> FixedOffset { + let date = CFDate::from_naive_utc(date); + FixedOffset::east(self.seconds_from_gmt(date) as i32) + } + + #[cfg(feature = "with-chrono")] + pub fn from_offset(offset: FixedOffset) -> CFTimeZone { + CFTimeZone::new(offset.local_minus_utc() as f64) + } +} + +#[cfg(test)] +mod test { + use super::CFTimeZone; + + #[cfg(feature = "with-chrono")] + use chrono::{NaiveDateTime, FixedOffset}; + + #[test] + fn timezone_comparison() { + let system = CFTimeZone::system(); + let default = CFTimeZone::default(); + assert_eq!(system, default); + } + + #[test] + #[cfg(feature = "with-chrono")] + fn timezone_chrono_conversion() { + let offset = FixedOffset::west(28800); + let tz = CFTimeZone::from_offset(offset); + let converted = tz.offset_at_date(NaiveDateTime::from_timestamp(0, 0)); + assert_eq!(offset, converted); + } +} diff --git a/core-foundation-0.4.6/src/url.rs b/core-foundation-0.4.6/src/url.rs new file mode 100644 index 000000000..85e05f351 --- /dev/null +++ b/core-foundation-0.4.6/src/url.rs @@ -0,0 +1,164 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A URL type for Core Foundation. + +pub use core_foundation_sys::url::*; + +use base::{TCFType, CFIndex}; +use string::{CFString}; + +use core_foundation_sys::base::{kCFAllocatorDefault, CFRelease, Boolean}; +use std::fmt; +use std::ptr; +use std::path::{Path, PathBuf}; +use std::mem; + +use libc::{strlen, PATH_MAX}; + +#[cfg(unix)] +use std::os::unix::ffi::OsStrExt; +#[cfg(unix)] +use std::ffi::OsStr; + +pub struct CFURL(CFURLRef); + +impl Drop for CFURL { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFURL, CFURLRef, CFURLGetTypeID); + +impl fmt::Debug for CFURL { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + unsafe { + let string: CFString = TCFType::wrap_under_get_rule(CFURLGetString(self.0)); + write!(f, "{}", string.to_string()) + } + } +} + +impl CFURL { + pub fn from_path>(path: P, isDirectory: bool) -> Option { + let path_bytes; + #[cfg(unix)] + { + path_bytes = path.as_ref().as_os_str().as_bytes() + } + #[cfg(not(unix))] + { + // XXX: Getting non-valid UTF8 paths into CoreFoundation on Windows is going to be unpleasant + // CFURLGetWideFileSystemRepresentation might help + path_bytes = match path.as_ref().to_str() { + Some(path) => path, + None => return None, + } + } + + unsafe { + let url_ref = CFURLCreateFromFileSystemRepresentation(ptr::null_mut(), path_bytes.as_ptr(), path_bytes.len() as CFIndex, isDirectory as u8); + if url_ref.is_null() { + return None; + } + Some(TCFType::wrap_under_create_rule(url_ref)) + } + } + + pub fn from_file_system_path(filePath: CFString, pathStyle: CFURLPathStyle, isDirectory: bool) -> CFURL { + unsafe { + let url_ref = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, filePath.as_concrete_TypeRef(), pathStyle, isDirectory as u8); + TCFType::wrap_under_create_rule(url_ref) + } + } + + #[cfg(unix)] + pub fn to_path(&self) -> Option { + // implementing this on Windows is more complicated because of the different OsStr representation + unsafe { + let mut buf: [u8; PATH_MAX as usize] = mem::uninitialized(); + let result = CFURLGetFileSystemRepresentation(self.0, true as Boolean, buf.as_mut_ptr(), buf.len() as CFIndex); + if result == false as Boolean { + return None; + } + let len = strlen(buf.as_ptr() as *const i8); + let path = OsStr::from_bytes(&buf[0..len]); + Some(PathBuf::from(path)) + } + } + + pub fn get_string(&self) -> CFString { + unsafe { + TCFType::wrap_under_get_rule(CFURLGetString(self.0)) + } + } + + pub fn get_file_system_path(&self, pathStyle: CFURLPathStyle) -> CFString { + unsafe { + TCFType::wrap_under_create_rule(CFURLCopyFileSystemPath(self.as_concrete_TypeRef(), pathStyle)) + } + } + + pub fn absolute(&self) -> CFURL { + unsafe { + TCFType::wrap_under_create_rule(CFURLCopyAbsoluteURL(self.as_concrete_TypeRef())) + } + } +} + +#[test] +fn file_url_from_path() { + let path = "/usr/local/foo/"; + let cfstr_path = CFString::from_static_string(path); + let cfurl = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); + assert_eq!(cfurl.get_string().to_string(), "file:///usr/local/foo/"); +} + +#[cfg(unix)] +#[test] +fn non_utf8() { + use std::ffi::OsStr; + let path = Path::new(OsStr::from_bytes(b"/\xC0/blame")); + let cfurl = CFURL::from_path(path, false).unwrap(); + assert_eq!(cfurl.to_path().unwrap(), path); + let len = unsafe { CFURLGetBytes(cfurl.as_concrete_TypeRef(), ptr::null_mut(), 0) }; + assert_eq!(len, 17); +} + +#[test] +fn absolute_file_url() { + use core_foundation_sys::url::CFURLCreateWithFileSystemPathRelativeToBase; + use std::path::PathBuf; + + let path = "/usr/local/foo"; + let file = "bar"; + + let cfstr_path = CFString::from_static_string(path); + let cfstr_file = CFString::from_static_string(file); + let cfurl_base = CFURL::from_file_system_path(cfstr_path, kCFURLPOSIXPathStyle, true); + let cfurl_relative: CFURL = unsafe { + let url_ref = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorDefault, + cfstr_file.as_concrete_TypeRef(), + kCFURLPOSIXPathStyle, + false as u8, + cfurl_base.as_concrete_TypeRef()); + TCFType::wrap_under_create_rule(url_ref) + }; + + let mut absolute_path = PathBuf::from(path); + absolute_path.push(file); + + assert_eq!(cfurl_relative.get_file_system_path(kCFURLPOSIXPathStyle).to_string(), file); + assert_eq!(cfurl_relative.absolute().get_file_system_path(kCFURLPOSIXPathStyle).to_string(), + absolute_path.to_str().unwrap()); +} diff --git a/core-foundation-0.4.6/src/uuid.rs b/core-foundation-0.4.6/src/uuid.rs new file mode 100644 index 000000000..3396c1659 --- /dev/null +++ b/core-foundation-0.4.6/src/uuid.rs @@ -0,0 +1,118 @@ +// Copyright 2013 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Core Foundation UUID objects. + +#[cfg(feature = "with-uuid")] +extern crate uuid; + +pub use core_foundation_sys::uuid::*; +use core_foundation_sys::base::{CFRelease, kCFAllocatorDefault}; + +use base::TCFType; + +#[cfg(feature = "with-uuid")] +use self::uuid::Uuid; + +/// A UUID. +pub struct CFUUID(CFUUIDRef); + +impl Drop for CFUUID { + fn drop(&mut self) { + unsafe { + CFRelease(self.as_CFTypeRef()) + } + } +} + +impl_TCFType!(CFUUID, CFUUIDRef, CFUUIDGetTypeID); +impl_CFTypeDescription!(CFUUID); + +impl CFUUID { + #[inline] + pub fn new() -> CFUUID { + unsafe { + let uuid_ref = CFUUIDCreate(kCFAllocatorDefault); + TCFType::wrap_under_create_rule(uuid_ref) + } + } +} + +#[cfg(feature = "with-uuid")] +impl Into for CFUUID { + fn into(self) -> Uuid { + let b = unsafe { + CFUUIDGetUUIDBytes(self.0) + }; + let bytes = [ + b.byte0, + b.byte1, + b.byte2, + b.byte3, + b.byte4, + b.byte5, + b.byte6, + b.byte7, + b.byte8, + b.byte9, + b.byte10, + b.byte11, + b.byte12, + b.byte13, + b.byte14, + b.byte15, + ]; + Uuid::from_bytes(&bytes).unwrap() + } +} + +#[cfg(feature = "with-uuid")] +impl From for CFUUID { + fn from(uuid: Uuid) -> CFUUID { + let b = uuid.as_bytes(); + let bytes = CFUUIDBytes { + byte0: b[0], + byte1: b[1], + byte2: b[2], + byte3: b[3], + byte4: b[4], + byte5: b[5], + byte6: b[6], + byte7: b[7], + byte8: b[8], + byte9: b[9], + byte10: b[10], + byte11: b[11], + byte12: b[12], + byte13: b[13], + byte14: b[14], + byte15: b[15], + }; + unsafe { + let uuid_ref = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, bytes); + TCFType::wrap_under_create_rule(uuid_ref) + } + } +} + + +#[cfg(test)] +#[cfg(feature = "with-uuid")] +mod test { + use super::CFUUID; + use uuid::Uuid; + + #[test] + fn uuid_conversion() { + let cf_uuid = CFUUID::new(); + let uuid: Uuid = cf_uuid.clone().into(); + let converted = CFUUID::from(uuid); + assert!(cf_uuid == converted); + } +} diff --git a/core-foundation-sys-0.4.6/.cargo-checksum.json b/core-foundation-sys-0.4.6/.cargo-checksum.json new file mode 100644 index 000000000..009c689fb --- /dev/null +++ b/core-foundation-sys-0.4.6/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"152195421a2e6497a8179195672e9d4ee8e45ed8c465b626f1606d27a08ebcd5"} \ No newline at end of file diff --git a/core-foundation-sys-0.4.6/Cargo.toml b/core-foundation-sys-0.4.6/Cargo.toml new file mode 100644 index 000000000..68160623b --- /dev/null +++ b/core-foundation-sys-0.4.6/Cargo.toml @@ -0,0 +1,27 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "core-foundation-sys" +version = "0.4.6" +authors = ["The Servo Project Developers"] +build = "build.rs" +description = "Bindings to Core Foundation for OS X" +homepage = "https://github.com/servo/core-foundation-rs" +license = "MIT / Apache-2.0" +repository = "https://github.com/servo/core-foundation-rs" +[dependencies.libc] +version = "0.2" + +[features] +mac_os_10_7_support = [] +mac_os_10_8_features = [] diff --git a/core-foundation-sys-0.4.6/build.rs b/core-foundation-sys-0.4.6/build.rs new file mode 100644 index 000000000..1f03b0602 --- /dev/null +++ b/core-foundation-sys-0.4.6/build.rs @@ -0,0 +1,14 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + if std::env::var("TARGET").unwrap().contains("-apple") { + println!("cargo:rustc-link-lib=framework=CoreFoundation"); + } +} diff --git a/core-foundation-sys-0.4.6/src/array.rs b/core-foundation-sys-0.4.6/src/array.rs new file mode 100644 index 000000000..8b0ef2980 --- /dev/null +++ b/core-foundation-sys-0.4.6/src/array.rs @@ -0,0 +1,55 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::c_void; + +use base::{CFRange, CFIndex, CFAllocatorRef, CFTypeID, Boolean}; +use string::CFStringRef; + +pub type CFArrayRetainCallBack = extern "C" fn(allocator: CFAllocatorRef, value: *const c_void) -> *const c_void; +pub type CFArrayReleaseCallBack = extern "C" fn(allocator: CFAllocatorRef, value: *const c_void); +pub type CFArrayCopyDescriptionCallBack = extern "C" fn(value: *const c_void) -> CFStringRef; +pub type CFArrayEqualCallBack = extern "C" fn(value1: *const c_void, value2: *const c_void) -> Boolean; + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CFArrayCallBacks { + pub version: CFIndex, + pub retain: CFArrayRetainCallBack, + pub release: CFArrayReleaseCallBack, + pub copyDescription: CFArrayCopyDescriptionCallBack, + pub equal: CFArrayEqualCallBack, +} + +#[repr(C)] +pub struct __CFArray(c_void); + +pub type CFArrayRef = *const __CFArray; + +extern { + /* + * CFArray.h + */ + pub static kCFTypeArrayCallBacks: CFArrayCallBacks; + + pub fn CFArrayCreate(allocator: CFAllocatorRef, values: *const *const c_void, + numValues: CFIndex, callBacks: *const CFArrayCallBacks) -> CFArrayRef; + pub fn CFArrayCreateCopy(allocator: CFAllocatorRef , theArray: CFArrayRef) -> CFArrayRef; + + // CFArrayBSearchValues + // CFArrayContainsValue + pub fn CFArrayGetCount(theArray: CFArrayRef) -> CFIndex; + // CFArrayGetCountOfValue + // CFArrayGetFirstIndexOfValue + // CFArrayGetLastIndexOfValue + pub fn CFArrayGetValues(theArray: CFArrayRef, range: CFRange, values: *mut *const c_void); + pub fn CFArrayGetValueAtIndex(theArray: CFArrayRef, idx: CFIndex) -> *const c_void; + // CFArrayApplyFunction + pub fn CFArrayGetTypeID() -> CFTypeID; +} diff --git a/core-foundation-sys-0.4.6/src/base.rs b/core-foundation-sys-0.4.6/src/base.rs new file mode 100644 index 000000000..2d63d8bf4 --- /dev/null +++ b/core-foundation-sys-0.4.6/src/base.rs @@ -0,0 +1,127 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp::Ordering; +use libc::{c_uint, c_long, c_ulong, c_void, c_int}; +use string::CFStringRef; + +pub type Boolean = u8; +pub type CFIndex = c_long; +pub type mach_port_t = c_uint; +pub type CFAllocatorRef = *const c_void; +pub type CFNullRef = *const c_void; +pub type CFHashCode = c_ulong; +pub type CFTypeID = c_ulong; +pub type CFTypeRef = *const c_void; +pub type CFOptionFlags = u32; +pub type OSStatus = i32; +pub type SInt32 = c_int; + +#[repr(i64)] +#[derive(Clone, Copy)] +pub enum CFComparisonResult { + LessThan = -1, + EqualTo = 0, + GreaterThan = 1, +} + +impl Into for CFComparisonResult { + fn into(self) -> Ordering { + match self { + CFComparisonResult::LessThan => Ordering::Less, + CFComparisonResult::EqualTo => Ordering::Equal, + CFComparisonResult::GreaterThan => Ordering::Greater + } + } +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CFRange { + pub location: CFIndex, + pub length: CFIndex +} + +// for back-compat +impl CFRange { + pub fn init(location: CFIndex, length: CFIndex) -> CFRange { + CFRange { + location: location, + length: length, + } + } +} + +pub type CFAllocatorRetainCallBack = extern "C" fn(info: *mut c_void) -> *mut c_void; +pub type CFAllocatorReleaseCallBack = extern "C" fn(info: *mut c_void); +pub type CFAllocatorCopyDescriptionCallBack = extern "C" fn(info: *mut c_void) -> CFStringRef; +pub type CFAllocatorAllocateCallBack = extern "C" fn(allocSize: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> *mut c_void; +pub type CFAllocatorReallocateCallBack = extern "C" fn(ptr: *mut c_void, newsize: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> *mut c_void; +pub type CFAllocatorDeallocateCallBack = extern "C" fn(ptr: *mut c_void, info: *mut c_void); +pub type CFAllocatorPreferredSizeCallBack = extern "C" fn(size: CFIndex, hint: CFOptionFlags, info: *mut c_void) -> CFIndex; + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CFAllocatorContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: CFAllocatorRetainCallBack, + pub release: CFAllocatorReleaseCallBack, + pub copyDescription: CFAllocatorCopyDescriptionCallBack, + pub allocate: CFAllocatorAllocateCallBack, + pub reallocate: CFAllocatorReallocateCallBack, + pub deallocate: CFAllocatorDeallocateCallBack, + pub preferredSize: CFAllocatorPreferredSizeCallBack +} + +extern { + /* + * CFBase.h + */ + + /* CFAllocator Reference */ + + pub static kCFAllocatorDefault: CFAllocatorRef; + pub static kCFAllocatorSystemDefault: CFAllocatorRef; + pub static kCFAllocatorMalloc: CFAllocatorRef; + pub static kCFAllocatorMallocZone: CFAllocatorRef; + pub static kCFAllocatorNull: CFAllocatorRef; + pub static kCFAllocatorUseContext: CFAllocatorRef; + + pub fn CFAllocatorCreate(allocator: CFAllocatorRef, context: *mut CFAllocatorContext) -> CFAllocatorRef; + pub fn CFAllocatorAllocate(allocator: CFAllocatorRef, size: CFIndex, hint: CFOptionFlags) -> *mut c_void; + pub fn CFAllocatorDeallocate(allocator: CFAllocatorRef, ptr: *mut c_void); + pub fn CFAllocatorGetPreferredSizeForSize(allocator: CFAllocatorRef, size: CFIndex, hint: CFOptionFlags) -> CFIndex; + pub fn CFAllocatorReallocate(allocator: CFAllocatorRef, ptr: *mut c_void, newsize: CFIndex, hint: CFOptionFlags) -> *mut c_void; + pub fn CFAllocatorGetDefault() -> CFAllocatorRef; + pub fn CFAllocatorSetDefault(allocator: CFAllocatorRef); + pub fn CFAllocatorGetContext(allocator: CFAllocatorRef, context: *mut CFAllocatorContext); + pub fn CFAllocatorGetTypeID() -> CFTypeID; + + /* CFNull Reference */ + + pub static kCFNull: CFNullRef; + + /* CFType Reference */ + + //fn CFCopyTypeIDDescription + //fn CFGetAllocator + pub fn CFCopyDescription(cf: CFTypeRef) -> CFStringRef; + pub fn CFEqual(cf1: CFTypeRef, cf2: CFTypeRef) -> Boolean; + pub fn CFGetRetainCount(cf: CFTypeRef) -> CFIndex; + pub fn CFGetTypeID(cf: CFTypeRef) -> CFTypeID; + pub fn CFHash(cf: CFTypeRef) -> CFHashCode; + //fn CFMakeCollectable + pub fn CFRelease(cf: CFTypeRef); + pub fn CFRetain(cf: CFTypeRef) -> CFTypeRef; + pub fn CFShow(obj: CFTypeRef); + + /* Base Utilities Reference */ + // N.B. Some things missing here. +} diff --git a/core-foundation-sys-0.4.6/src/bundle.rs b/core-foundation-sys-0.4.6/src/bundle.rs new file mode 100644 index 000000000..3f8c0b376 --- /dev/null +++ b/core-foundation-sys-0.4.6/src/bundle.rs @@ -0,0 +1,36 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::c_void; + +use base::{CFTypeID, CFAllocatorRef}; +use url::CFURLRef; +use dictionary::CFDictionaryRef; +use string::CFStringRef; + +#[repr(C)] +pub struct __CFBundle(c_void); + +pub type CFBundleRef = *const __CFBundle; + +extern { + /* + * CFBundle.h + */ + pub fn CFBundleCreate(allocator: CFAllocatorRef, bundleURL: CFURLRef) -> CFBundleRef; + + pub fn CFBundleGetBundleWithIdentifier(bundleID: CFStringRef) -> CFBundleRef; + pub fn CFBundleGetFunctionPointerForName(bundle: CFBundleRef, function_name: CFStringRef) -> *const c_void; + pub fn CFBundleGetMainBundle() -> CFBundleRef; + pub fn CFBundleGetInfoDictionary(bundle: CFBundleRef) -> CFDictionaryRef; + + pub fn CFBundleGetTypeID() -> CFTypeID; + pub fn CFBundleCopyExecutableURL(bundle: CFBundleRef) -> CFURLRef; + pub fn CFBundleCopyPrivateFrameworksURL(bundle: CFBundleRef) -> CFURLRef; +} diff --git a/core-foundation-sys-0.4.6/src/data.rs b/core-foundation-sys-0.4.6/src/data.rs new file mode 100644 index 000000000..6a42b2b38 --- /dev/null +++ b/core-foundation-sys-0.4.6/src/data.rs @@ -0,0 +1,22 @@ +use libc::c_void; + +use base::{CFAllocatorRef, CFTypeID, CFIndex}; + +#[repr(C)] +pub struct __CFData(c_void); + +pub type CFDataRef = *const __CFData; + +extern { + /* + * CFData.h + */ + + pub fn CFDataCreate(allocator: CFAllocatorRef, + bytes: *const u8, length: CFIndex) -> CFDataRef; + //fn CFDataFind + pub fn CFDataGetBytePtr(theData: CFDataRef) -> *const u8; + pub fn CFDataGetLength(theData: CFDataRef) -> CFIndex; + + pub fn CFDataGetTypeID() -> CFTypeID; +} diff --git a/core-foundation-sys-0.4.6/src/date.rs b/core-foundation-sys-0.4.6/src/date.rs new file mode 100644 index 000000000..6ae91f2eb --- /dev/null +++ b/core-foundation-sys-0.4.6/src/date.rs @@ -0,0 +1,34 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::c_void; + +use base::{CFAllocatorRef, CFComparisonResult, CFTypeID}; + +#[repr(C)] +pub struct __CFDate(c_void); + +pub type CFDateRef = *const __CFDate; + +pub type CFTimeInterval = f64; +pub type CFAbsoluteTime = CFTimeInterval; + +extern { + pub static kCFAbsoluteTimeIntervalSince1904: CFTimeInterval; + pub static kCFAbsoluteTimeIntervalSince1970: CFTimeInterval; + + pub fn CFAbsoluteTimeGetCurrent() -> CFAbsoluteTime; + + pub fn CFDateCreate(allocator: CFAllocatorRef, at: CFAbsoluteTime) -> CFDateRef; + pub fn CFDateGetAbsoluteTime(date: CFDateRef) -> CFAbsoluteTime; + pub fn CFDateGetTimeIntervalSinceDate(date: CFDateRef, other: CFDateRef) -> CFTimeInterval; + pub fn CFDateCompare(date: CFDateRef, other: CFDateRef, context: *mut c_void) -> CFComparisonResult; + + pub fn CFDateGetTypeID() -> CFTypeID; +} diff --git a/core-foundation-sys-0.4.6/src/dictionary.rs b/core-foundation-sys-0.4.6/src/dictionary.rs new file mode 100644 index 000000000..6626cffeb --- /dev/null +++ b/core-foundation-sys-0.4.6/src/dictionary.rs @@ -0,0 +1,77 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::{c_void}; + +use base::{CFAllocatorRef, CFHashCode, CFIndex, CFTypeID, Boolean}; +use string::CFStringRef; + +pub type CFDictionaryApplierFunction = extern "C" fn(key: *const c_void, value: *const c_void, context: *mut c_void); + +pub type CFDictionaryRetainCallBack = extern "C" fn(allocator: CFAllocatorRef, value: *const c_void) -> *const c_void; +pub type CFDictionaryReleaseCallBack = extern "C" fn(allocator: CFAllocatorRef, value: *const c_void); +pub type CFDictionaryCopyDescriptionCallBack = extern "C" fn(value: *const c_void) -> CFStringRef; +pub type CFDictionaryEqualCallBack = extern "C" fn(value1: *const c_void, value2: *const c_void) -> Boolean; +pub type CFDictionaryHashCallBack = extern "C" fn(value: *const c_void) -> CFHashCode; + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CFDictionaryKeyCallBacks { + pub version: CFIndex, + pub retain: CFDictionaryRetainCallBack, + pub release: CFDictionaryReleaseCallBack, + pub copyDescription: CFDictionaryCopyDescriptionCallBack, + pub equal: CFDictionaryEqualCallBack, + pub hash: CFDictionaryHashCallBack +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CFDictionaryValueCallBacks { + pub version: CFIndex, + pub retain: CFDictionaryRetainCallBack, + pub release: CFDictionaryReleaseCallBack, + pub copyDescription: CFDictionaryCopyDescriptionCallBack, + pub equal: CFDictionaryEqualCallBack +} + +#[repr(C)] +pub struct __CFDictionary(c_void); + +pub type CFDictionaryRef = *const __CFDictionary; +pub type CFMutableDictionaryRef = *const __CFDictionary; + +extern { + /* + * CFDictionary.h + */ + + pub static kCFTypeDictionaryKeyCallBacks: CFDictionaryKeyCallBacks; + pub static kCFTypeDictionaryValueCallBacks: CFDictionaryValueCallBacks; + + pub fn CFDictionaryContainsKey(theDict: CFDictionaryRef, key: *const c_void) -> Boolean; + pub fn CFDictionaryCreate(allocator: CFAllocatorRef, keys: *const *const c_void, values: *const *const c_void, + numValues: CFIndex, keyCallBacks: *const CFDictionaryKeyCallBacks, + valueCallBacks: *const CFDictionaryValueCallBacks) + -> CFDictionaryRef; + pub fn CFDictionaryGetCount(theDict: CFDictionaryRef) -> CFIndex; + pub fn CFDictionaryGetTypeID() -> CFTypeID; + pub fn CFDictionaryGetValueIfPresent(theDict: CFDictionaryRef, key: *const c_void, value: *mut *const c_void) + -> Boolean; + pub fn CFDictionaryApplyFunction(theDict: CFDictionaryRef, + applier: CFDictionaryApplierFunction, + context: *mut c_void); + pub fn CFDictionarySetValue(theDict: CFMutableDictionaryRef, + key: *const c_void, + value: *const c_void); + pub fn CFDictionaryGetKeysAndValues(theDict: CFDictionaryRef, + keys: *mut *const c_void, + values: *mut *const c_void); + +} diff --git a/core-foundation-sys-0.4.6/src/error.rs b/core-foundation-sys-0.4.6/src/error.rs new file mode 100644 index 000000000..68097dad7 --- /dev/null +++ b/core-foundation-sys-0.4.6/src/error.rs @@ -0,0 +1,32 @@ +// Copyright 2016 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::c_void; + +use base::{CFTypeID, CFIndex}; +use string::CFStringRef; + +#[repr(C)] +pub struct __CFError(c_void); + +pub type CFErrorRef = *mut __CFError; + +extern "C" { + pub fn CFErrorGetTypeID() -> CFTypeID; + + pub static kCFErrorDomainPOSIX: CFStringRef; + pub static kCFErrorDomainOSStatus: CFStringRef; + pub static kCFErrorDomainMach: CFStringRef; + pub static kCFErrorDomainCocoa: CFStringRef; + + pub fn CFErrorGetDomain(err: CFErrorRef) -> CFStringRef; + pub fn CFErrorGetCode(err: CFErrorRef) -> CFIndex; + + pub fn CFErrorCopyDescription(err: CFErrorRef) -> CFStringRef; +} diff --git a/core-foundation-sys-0.4.6/src/lib.rs b/core-foundation-sys-0.4.6/src/lib.rs new file mode 100644 index 000000000..d2744e2a0 --- /dev/null +++ b/core-foundation-sys-0.4.6/src/lib.rs @@ -0,0 +1,30 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals, improper_ctypes)] + +#![cfg_attr(all(feature="mac_os_10_7_support", feature="mac_os_10_8_features"), feature(linkage))] // back-compat requires weak linkage + +extern crate libc; + +pub mod array; +pub mod base; +pub mod bundle; +pub mod data; +pub mod date; +pub mod dictionary; +pub mod error; +pub mod messageport; +pub mod number; +pub mod propertylist; +pub mod runloop; +pub mod set; +pub mod string; +pub mod timezone; +pub mod url; +pub mod uuid; diff --git a/core-foundation-sys-0.4.6/src/messageport.rs b/core-foundation-sys-0.4.6/src/messageport.rs new file mode 100644 index 000000000..9b15a4d06 --- /dev/null +++ b/core-foundation-sys-0.4.6/src/messageport.rs @@ -0,0 +1,79 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::c_void; + +use base::{CFAllocatorRef, CFIndex, CFTypeID, Boolean}; +use data::CFDataRef; +use date::CFTimeInterval; +use runloop::CFRunLoopSourceRef; +use string::CFStringRef; + +#[repr(C)] +#[derive(Copy, Clone)] +#[derive(Debug)] +pub struct CFMessagePortContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: Option *const c_void>, + pub release: Option, + pub copyDescription: Option CFStringRef>, +} + +pub type CFMessagePortCallBack = Option< + unsafe extern fn(local: CFMessagePortRef, + msgid: i32, + data: CFDataRef, + info: *mut c_void) -> CFDataRef>; + +pub type CFMessagePortInvalidationCallBack = Option< + unsafe extern "C" fn(ms: CFMessagePortRef, info: *mut c_void)>; + +#[repr(C)] +pub struct __CFMessagePort(c_void); +pub type CFMessagePortRef = *const __CFMessagePort; + +extern { + /* + * CFMessagePort.h + */ + pub fn CFMessagePortGetTypeID() -> CFTypeID; + pub fn CFMessagePortCreateLocal(allocator: CFAllocatorRef, + name: CFStringRef, + callout: CFMessagePortCallBack, + context: *const CFMessagePortContext, + shouldFreeInfo: *mut Boolean) + -> CFMessagePortRef; + pub fn CFMessagePortCreateRemote(allocator: CFAllocatorRef, + name: CFStringRef) -> CFMessagePortRef; + pub fn CFMessagePortIsRemote(ms: CFMessagePortRef) -> Boolean; + pub fn CFMessagePortGetName(ms: CFMessagePortRef) -> CFStringRef; + pub fn CFMessagePortSetName(ms: CFMessagePortRef, newName: CFStringRef) + -> Boolean; + pub fn CFMessagePortGetContext(ms: CFMessagePortRef, + context: *mut CFMessagePortContext); + pub fn CFMessagePortInvalidate(ms: CFMessagePortRef); + pub fn CFMessagePortIsValid(ms: CFMessagePortRef) -> Boolean; + pub fn CFMessagePortGetInvalidationCallBack(ms: CFMessagePortRef) + -> CFMessagePortInvalidationCallBack; + pub fn CFMessagePortSetInvalidationCallBack(ms: CFMessagePortRef, + callout: CFMessagePortInvalidationCallBack); + pub fn CFMessagePortSendRequest(remote: CFMessagePortRef, msgid: i32, + data: CFDataRef, + sendTimeout: CFTimeInterval, + rcvTimeout: CFTimeInterval, + replyMode: CFStringRef, + returnData: *mut CFDataRef) -> i32; + pub fn CFMessagePortCreateRunLoopSource(allocator: CFAllocatorRef, + local: CFMessagePortRef, + order: CFIndex) + -> CFRunLoopSourceRef; + // CFMessagePortSetDispatchQueue +} diff --git a/core-foundation-sys-0.4.6/src/number.rs b/core-foundation-sys-0.4.6/src/number.rs new file mode 100644 index 000000000..8ea0d286d --- /dev/null +++ b/core-foundation-sys-0.4.6/src/number.rs @@ -0,0 +1,60 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::c_void; + +use base::{CFAllocatorRef, CFTypeID, CFComparisonResult}; + +#[repr(C)] +pub struct __CFBoolean(c_void); + +pub type CFBooleanRef = *const __CFBoolean; + +pub type CFNumberType = u32; + +// members of enum CFNumberType +// static kCFNumberSInt8Type: CFNumberType = 1; +// static kCFNumberSInt16Type: CFNumberType = 2; +pub static kCFNumberSInt32Type: CFNumberType = 3; +pub static kCFNumberSInt64Type: CFNumberType = 4; +pub static kCFNumberFloat32Type: CFNumberType = 5; +pub static kCFNumberFloat64Type: CFNumberType = 6; +// static kCFNumberCharType: CFNumberType = 7; +// static kCFNumberShortType: CFNumberType = 8; +// static kCFNumberIntType: CFNumberType = 9; +// static kCFNumberLongType: CFNumberType = 10; +// static kCFNumberLongLongType: CFNumberType = 11; +// static kCFNumberFloatType: CFNumberType = 12; +// static kCFNumberDoubleType: CFNumberType = 13; +// static kCFNumberCFIndexType: CFNumberType = 14; +// static kCFNumberNSIntegerType: CFNumberType = 15; +// static kCFNumberCGFloatType: CFNumberType = 16; +// static kCFNumberMaxType: CFNumberType = 16; + +// This is an enum due to zero-sized types warnings. +// For more details see https://github.com/rust-lang/rust/issues/27303 +pub enum __CFNumber {} + +pub type CFNumberRef = *const __CFNumber; + +extern { + /* + * CFNumber.h + */ + pub static kCFBooleanTrue: CFBooleanRef; + pub static kCFBooleanFalse: CFBooleanRef; + + pub fn CFBooleanGetTypeID() -> CFTypeID; + pub fn CFNumberCreate(allocator: CFAllocatorRef, theType: CFNumberType, valuePtr: *const c_void) + -> CFNumberRef; + //fn CFNumberGetByteSize + pub fn CFNumberGetValue(number: CFNumberRef, theType: CFNumberType, valuePtr: *mut c_void) -> bool; + pub fn CFNumberCompare(date: CFNumberRef, other: CFNumberRef, context: *mut c_void) -> CFComparisonResult; + pub fn CFNumberGetTypeID() -> CFTypeID; +} diff --git a/core-foundation-sys-0.4.6/src/propertylist.rs b/core-foundation-sys-0.4.6/src/propertylist.rs new file mode 100644 index 000000000..2396ef998 --- /dev/null +++ b/core-foundation-sys-0.4.6/src/propertylist.rs @@ -0,0 +1,37 @@ +use base::{CFAllocatorRef, CFIndex, CFOptionFlags, CFTypeRef}; +use data::CFDataRef; +use error::CFErrorRef; + +pub type CFPropertyListRef = CFTypeRef; + +pub type CFPropertyListFormat = CFIndex; +pub const kCFPropertyListOpenStepFormat: CFPropertyListFormat = 1; +pub const kCFPropertyListXMLFormat_v1_0: CFPropertyListFormat = 100; +pub const kCFPropertyListBinaryFormat_v1_0: CFPropertyListFormat = 200; + +pub type CFPropertyListMutabilityOptions = CFOptionFlags; +pub const kCFPropertyListImmutable: CFPropertyListMutabilityOptions = 0; +pub const kCFPropertyListMutableContainers: CFPropertyListMutabilityOptions = 1; +pub const kCFPropertyListMutableContainersAndLeaves: CFPropertyListMutabilityOptions = 2; + +extern "C" { + // CFPropertyList.h + // + + // fn CFPropertyListCreateDeepCopy + // fn CFPropertyListIsValid + pub fn CFPropertyListCreateWithData(allocator: CFAllocatorRef, + data: CFDataRef, + options: CFPropertyListMutabilityOptions, + format: *mut CFPropertyListFormat, + error: *mut CFErrorRef) + -> CFPropertyListRef; + // fn CFPropertyListCreateWithStream + // fn CFPropertyListWrite + pub fn CFPropertyListCreateData(allocator: CFAllocatorRef, + propertyList: CFPropertyListRef, + format: CFPropertyListFormat, + options: CFOptionFlags, + error: *mut CFErrorRef) + -> CFDataRef; +} diff --git a/core-foundation-sys-0.4.6/src/runloop.rs b/core-foundation-sys-0.4.6/src/runloop.rs new file mode 100644 index 000000000..86414a5ee --- /dev/null +++ b/core-foundation-sys-0.4.6/src/runloop.rs @@ -0,0 +1,164 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::c_void; + +use array::CFArrayRef; +use base::{Boolean, CFIndex, CFTypeID, CFAllocatorRef, CFOptionFlags, CFHashCode, mach_port_t}; +use date::{CFAbsoluteTime, CFTimeInterval}; +use string::CFStringRef; + +#[repr(C)] +pub struct __CFRunLoop(c_void); + +pub type CFRunLoopRef = *const __CFRunLoop; + +#[repr(C)] +pub struct __CFRunLoopSource(c_void); + +pub type CFRunLoopSourceRef = *const __CFRunLoopSource; + +#[repr(C)] +pub struct __CFRunLoopObserver(c_void); + +pub type CFRunLoopObserverRef = *const __CFRunLoopObserver; + +// Reasons for CFRunLoopRunInMode() to Return +pub const kCFRunLoopRunFinished: i32 = 1; +pub const kCFRunLoopRunStopped: i32 = 2; +pub const kCFRunLoopRunTimedOut: i32 = 3; +pub const kCFRunLoopRunHandledSource: i32 = 4; + +// Run Loop Observer Activities +//typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { +pub type CFRunLoopActivity = CFOptionFlags; +pub const kCFRunLoopEntry: CFOptionFlags = 1 << 0; +pub const kCFRunLoopBeforeTimers: CFOptionFlags = 1 << 1; +pub const kCFRunLoopBeforeSources: CFOptionFlags = 1 << 2; +pub const kCFRunLoopBeforeWaiting: CFOptionFlags = 1 << 5; +pub const kCFRunLoopAfterWaiting: CFOptionFlags = 1 << 6; +pub const kCFRunLoopExit: CFOptionFlags = 1 << 7; +pub const kCFRunLoopAllActivities: CFOptionFlags = 0x0FFFFFFF; + +#[repr(C)] +pub struct CFRunLoopSourceContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: extern "C" fn (info: *const c_void) -> *const c_void, + pub release: extern "C" fn (info: *const c_void), + pub copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef, + pub equal: extern "C" fn (info1: *const c_void, info2: *const c_void) -> Boolean, + pub hash: extern "C" fn (info: *const c_void) -> CFHashCode, + pub schedule: extern "C" fn (info: *const c_void, rl: CFRunLoopRef, mode: CFStringRef), + pub cancel: extern "C" fn (info: *const c_void, rl: CFRunLoopRef, mode: CFStringRef), + pub perform: extern "C" fn (info: *const c_void), +} + +#[repr(C)] +pub struct CFRunLoopSourceContext1 { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: extern "C" fn (info: *const c_void) -> *const c_void, + pub release: extern "C" fn (info: *const c_void), + pub copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef, + pub equal: extern "C" fn (info1: *const c_void, info2: *const c_void) -> Boolean, + pub hash: extern "C" fn (info: *const c_void) -> CFHashCode, + // note that the following two fields are platform dependent in the C header, the ones here are for OS X + pub getPort: extern "C" fn (info: *mut c_void) -> mach_port_t, + pub perform: extern "C" fn (msg: *mut c_void, size: CFIndex, allocator: CFAllocatorRef, info: *mut c_void) -> *mut c_void, +} + +#[repr(C)] +pub struct CFRunLoopObserverContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: extern "C" fn (info: *const c_void) -> *const c_void, + pub release: extern "C" fn (info: *const c_void), + pub copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef, +} + +pub type CFRunLoopObserverCallBack = extern "C" fn (observer: CFRunLoopObserverRef, activity: CFRunLoopActivity, info: *mut c_void); + +#[repr(C)] +pub struct CFRunLoopTimerContext { + pub version: CFIndex, + pub info: *mut c_void, + pub retain: extern "C" fn (info: *const c_void) -> *const c_void, + pub release: extern "C" fn (info: *const c_void), + pub copyDescription: extern "C" fn (info: *const c_void) -> CFStringRef, +} + +pub type CFRunLoopTimerCallBack = extern "C" fn (timer: CFRunLoopTimerRef, info: *mut c_void); + +#[repr(C)] +pub struct __CFRunLoopTimer; + +pub type CFRunLoopTimerRef = *const __CFRunLoopTimer; + +extern { + /* + * CFRunLoop.h + */ + pub static kCFRunLoopDefaultMode: CFStringRef; + pub static kCFRunLoopCommonModes: CFStringRef; + pub fn CFRunLoopGetTypeID() -> CFTypeID; + pub fn CFRunLoopGetCurrent() -> CFRunLoopRef; + pub fn CFRunLoopGetMain() -> CFRunLoopRef; + pub fn CFRunLoopCopyCurrentMode(rl: CFRunLoopRef) -> CFStringRef; + pub fn CFRunLoopCopyAllModes(rl: CFRunLoopRef) -> CFArrayRef; + pub fn CFRunLoopAddCommonMode(rl: CFRunLoopRef, mode: CFStringRef); + pub fn CFRunLoopGetNextTimerFireDate(rl: CFRunLoopRef, mode: CFStringRef) -> CFAbsoluteTime; + pub fn CFRunLoopRun(); + pub fn CFRunLoopRunInMode(mode: CFStringRef, seconds: CFTimeInterval, returnAfterSourceHandled: Boolean) -> i32; + pub fn CFRunLoopIsWaiting(rl: CFRunLoopRef) -> Boolean; + pub fn CFRunLoopWakeUp(rl: CFRunLoopRef); + pub fn CFRunLoopStop(rl: CFRunLoopRef); + // fn CFRunLoopPerformBlock(rl: CFRunLoopRef, mode: CFTypeRef, block: void (^)(void)); + pub fn CFRunLoopContainsSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef) -> Boolean; + pub fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef); + pub fn CFRunLoopRemoveSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef); + pub fn CFRunLoopContainsObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef) -> Boolean; + pub fn CFRunLoopAddObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef); + pub fn CFRunLoopRemoveObserver(rl: CFRunLoopRef, observer: CFRunLoopObserverRef, mode: CFStringRef); + pub fn CFRunLoopContainsTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef) -> Boolean; + pub fn CFRunLoopAddTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef); + pub fn CFRunLoopRemoveTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef); + + pub fn CFRunLoopSourceGetTypeID() -> CFTypeID; + pub fn CFRunLoopSourceCreate(allocator: CFAllocatorRef, order: CFIndex, context: *mut CFRunLoopSourceContext) -> CFRunLoopSourceRef; + pub fn CFRunLoopSourceGetOrder(source: CFRunLoopSourceRef) -> CFIndex; + pub fn CFRunLoopSourceInvalidate(source: CFRunLoopSourceRef); + pub fn CFRunLoopSourceIsValid(source: CFRunLoopSourceRef) -> Boolean; + pub fn CFRunLoopSourceGetContext(source: CFRunLoopSourceRef, context: *mut CFRunLoopSourceContext); + pub fn CFRunLoopSourceSignal(source: CFRunLoopSourceRef); + + pub fn CFRunLoopObserverGetTypeID() -> CFTypeID; + pub fn CFRunLoopObserverCreate(allocator: CFAllocatorRef, activities: CFOptionFlags, repeats: Boolean, order: CFIndex, callout: CFRunLoopObserverCallBack, context: *mut CFRunLoopObserverContext) -> CFRunLoopObserverRef; + // fn CFRunLoopObserverCreateWithHandler(allocator: CFAllocatorRef, activities: CFOptionFlags, repeats: Boolean, order: CFIndex, block: void (^) (CFRunLoopObserverRef observer, CFRunLoopActivity activity)) -> CFRunLoopObserverRef; + pub fn CFRunLoopObserverGetActivities(observer: CFRunLoopObserverRef) -> CFOptionFlags; + pub fn CFRunLoopObserverDoesRepeat(observer: CFRunLoopObserverRef) -> Boolean; + pub fn CFRunLoopObserverGetOrder(observer: CFRunLoopObserverRef) -> CFIndex; + pub fn CFRunLoopObserverInvalidate(observer: CFRunLoopObserverRef); + pub fn CFRunLoopObserverIsValid(observer: CFRunLoopObserverRef) -> Boolean; + pub fn CFRunLoopObserverGetContext(observer: CFRunLoopObserverRef, context: *mut CFRunLoopObserverContext); + + pub fn CFRunLoopTimerGetTypeID() -> CFTypeID; + pub fn CFRunLoopTimerCreate(allocator: CFAllocatorRef, fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, callout: CFRunLoopTimerCallBack, context: *mut CFRunLoopTimerContext) -> CFRunLoopTimerRef; + // fn CFRunLoopTimerCreateWithHandler(allocator: CFAllocatorRef, fireDate: CFAbsoluteTime, interval: CFTimeInterval, flags: CFOptionFlags, order: CFIndex, block: void (^) (CFRunLoopTimerRef timer)) -> CFRunLoopTimerRef; + pub fn CFRunLoopTimerGetNextFireDate(timer: CFRunLoopTimerRef) -> CFAbsoluteTime; + pub fn CFRunLoopTimerSetNextFireDate(timer: CFRunLoopTimerRef, fireDate: CFAbsoluteTime); + pub fn CFRunLoopTimerGetInterval(timer: CFRunLoopTimerRef) -> CFTimeInterval; + pub fn CFRunLoopTimerDoesRepeat(timer: CFRunLoopTimerRef) -> Boolean; + pub fn CFRunLoopTimerGetOrder(timer: CFRunLoopTimerRef) -> CFIndex; + pub fn CFRunLoopTimerInvalidate(timer: CFRunLoopTimerRef); + pub fn CFRunLoopTimerIsValid(timer: CFRunLoopTimerRef) -> Boolean; + pub fn CFRunLoopTimerGetContext(timer: CFRunLoopTimerRef, context: *mut CFRunLoopTimerContext); + pub fn CFRunLoopTimerGetTolerance(timer: CFRunLoopTimerRef) -> CFTimeInterval; + pub fn CFRunLoopTimerSetTolerance(timer: CFRunLoopTimerRef, tolerance: CFTimeInterval); +} diff --git a/core-foundation-sys-0.4.6/src/set.rs b/core-foundation-sys-0.4.6/src/set.rs new file mode 100644 index 000000000..ca9c3c59a --- /dev/null +++ b/core-foundation-sys-0.4.6/src/set.rs @@ -0,0 +1,58 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::c_void; + +use base::{CFAllocatorRef, CFIndex, CFTypeID}; + +pub type CFSetApplierFunction = extern "C" fn (value: *const c_void, + context: *const c_void); +pub type CFSetRetainCallBack = *const u8; +pub type CFSetReleaseCallBack = *const u8; +pub type CFSetCopyDescriptionCallBack = *const u8; +pub type CFSetEqualCallBack = *const u8; +pub type CFSetHashCallBack = *const u8; + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct CFSetCallBacks { + pub version: CFIndex, + pub retain: CFSetRetainCallBack, + pub release: CFSetReleaseCallBack, + pub copyDescription: CFSetCopyDescriptionCallBack, + pub equal: CFSetEqualCallBack, + pub hash: CFSetHashCallBack, +} + +#[repr(C)] +pub struct __CFSet(c_void); + +pub type CFSetRef = *const __CFSet; + +extern { + /* + * CFSet.h + */ + + pub static kCFTypeSetCallBacks: CFSetCallBacks; + + /* Creating Sets */ + pub fn CFSetCreate(allocator: CFAllocatorRef, values: *const *const c_void, numValues: CFIndex, + callBacks: *const CFSetCallBacks) -> CFSetRef; + + /* Applying a Function to Set Members */ + pub fn CFSetApplyFunction(theSet: CFSetRef, + applier: CFSetApplierFunction, + context: *const c_void); + + pub fn CFSetGetCount(theSet: CFSetRef) -> CFIndex; + + pub fn CFSetGetTypeID() -> CFTypeID; +} + diff --git a/core-foundation-sys-0.4.6/src/string.rs b/core-foundation-sys-0.4.6/src/string.rs new file mode 100644 index 000000000..bdb1be704 --- /dev/null +++ b/core-foundation-sys-0.4.6/src/string.rs @@ -0,0 +1,319 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::{c_char, c_ushort, c_void}; + +use base::{Boolean, CFOptionFlags, CFIndex, CFAllocatorRef, CFRange, CFTypeID}; + +pub type UniChar = c_ushort; + +// CFString.h + +pub type CFStringCompareFlags = CFOptionFlags; +//static kCFCompareCaseInsensitive: CFStringCompareFlags = 1; +//static kCFCompareBackwards: CFStringCompareFlags = 4; +//static kCFCompareAnchored: CFStringCompareFlags = 8; +//static kCFCompareNonliteral: CFStringCompareFlags = 16; +//static kCFCompareLocalized: CFStringCompareFlags = 32; +//static kCFCompareNumerically: CFStringCompareFlags = 64; +//static kCFCompareDiacriticInsensitive: CFStringCompareFlags = 128; +//static kCFCompareWidthInsensitive: CFStringCompareFlags = 256; +//static kCFCompareForcedOrdering: CFStringCompareFlags = 512; + +pub type CFStringEncoding = u32; + +// OS X built-in encodings. + +//static kCFStringEncodingMacRoman: CFStringEncoding = 0; +//static kCFStringEncodingWindowsLatin1: CFStringEncoding = 0x0500; +//static kCFStringEncodingISOLatin1: CFStringEncoding = 0x0201; +//static kCFStringEncodingNextStepLatin: CFStringEncoding = 0x0B01; +//static kCFStringEncodingASCII: CFStringEncoding = 0x0600; +//static kCFStringEncodingUnicode: CFStringEncoding = 0x0100; +pub static kCFStringEncodingUTF8: CFStringEncoding = 0x08000100; +//static kCFStringEncodingNonLossyASCII: CFStringEncoding = 0x0BFF; + +//static kCFStringEncodingUTF16: CFStringEncoding = 0x0100; +//static kCFStringEncodingUTF16BE: CFStringEncoding = 0x10000100; +//static kCFStringEncodingUTF16LE: CFStringEncoding = 0x14000100; +//static kCFStringEncodingUTF32: CFStringEncoding = 0x0c000100; +//static kCFStringEncodingUTF32BE: CFStringEncoding = 0x18000100; +//static kCFStringEncodingUTF32LE: CFStringEncoding = 0x1c000100; + + +// CFStringEncodingExt.h + +pub type CFStringEncodings = CFIndex; + +// External encodings, except those defined above. +// Defined above: kCFStringEncodingMacRoman = 0 +//static kCFStringEncodingMacJapanese: CFStringEncoding = 1; +//static kCFStringEncodingMacChineseTrad: CFStringEncoding = 2; +//static kCFStringEncodingMacKorean: CFStringEncoding = 3; +//static kCFStringEncodingMacArabic: CFStringEncoding = 4; +//static kCFStringEncodingMacHebrew: CFStringEncoding = 5; +//static kCFStringEncodingMacGreek: CFStringEncoding = 6; +//static kCFStringEncodingMacCyrillic: CFStringEncoding = 7; +//static kCFStringEncodingMacDevanagari: CFStringEncoding = 9; +//static kCFStringEncodingMacGurmukhi: CFStringEncoding = 10; +//static kCFStringEncodingMacGujarati: CFStringEncoding = 11; +//static kCFStringEncodingMacOriya: CFStringEncoding = 12; +//static kCFStringEncodingMacBengali: CFStringEncoding = 13; +//static kCFStringEncodingMacTamil: CFStringEncoding = 14; +//static kCFStringEncodingMacTelugu: CFStringEncoding = 15; +//static kCFStringEncodingMacKannada: CFStringEncoding = 16; +//static kCFStringEncodingMacMalayalam: CFStringEncoding = 17; +//static kCFStringEncodingMacSinhalese: CFStringEncoding = 18; +//static kCFStringEncodingMacBurmese: CFStringEncoding = 19; +//static kCFStringEncodingMacKhmer: CFStringEncoding = 20; +//static kCFStringEncodingMacThai: CFStringEncoding = 21; +//static kCFStringEncodingMacLaotian: CFStringEncoding = 22; +//static kCFStringEncodingMacGeorgian: CFStringEncoding = 23; +//static kCFStringEncodingMacArmenian: CFStringEncoding = 24; +//static kCFStringEncodingMacChineseSimp: CFStringEncoding = 25; +//static kCFStringEncodingMacTibetan: CFStringEncoding = 26; +//static kCFStringEncodingMacMongolian: CFStringEncoding = 27; +//static kCFStringEncodingMacEthiopic: CFStringEncoding = 28; +//static kCFStringEncodingMacCentralEurRoman: CFStringEncoding = 29; +//static kCFStringEncodingMacVietnamese: CFStringEncoding = 30; +//static kCFStringEncodingMacExtArabic: CFStringEncoding = 31; +//static kCFStringEncodingMacSymbol: CFStringEncoding = 33; +//static kCFStringEncodingMacDingbats: CFStringEncoding = 34; +//static kCFStringEncodingMacTurkish: CFStringEncoding = 35; +//static kCFStringEncodingMacCroatian: CFStringEncoding = 36; +//static kCFStringEncodingMacIcelandic: CFStringEncoding = 37; +//static kCFStringEncodingMacRomanian: CFStringEncoding = 38; +//static kCFStringEncodingMacCeltic: CFStringEncoding = 39; +//static kCFStringEncodingMacGaelic: CFStringEncoding = 40; +//static kCFStringEncodingMacFarsi: CFStringEncoding = 0x8C; +//static kCFStringEncodingMacUkrainian: CFStringEncoding = 0x98; +//static kCFStringEncodingMacInuit: CFStringEncoding = 0xEC; +//static kCFStringEncodingMacVT100: CFStringEncoding = 0xFC; +//static kCFStringEncodingMacHFS: CFStringEncoding = 0xFF; +// Defined above: kCFStringEncodingISOLatin1 = 0x0201 +//static kCFStringEncodingISOLatin2: CFStringEncoding = 0x0202; +//static kCFStringEncodingISOLatin3: CFStringEncoding = 0x0203; +//static kCFStringEncodingISOLatin4: CFStringEncoding = 0x0204; +//static kCFStringEncodingISOLatinCyrillic: CFStringEncoding = 0x0205; +//static kCFStringEncodingISOLatinArabic: CFStringEncoding = 0x0206; +//static kCFStringEncodingISOLatinGreek: CFStringEncoding = 0x0207; +//static kCFStringEncodingISOLatinHebrew: CFStringEncoding = 0x0208; +//static kCFStringEncodingISOLatin5: CFStringEncoding = 0x0209; +//static kCFStringEncodingISOLatin6: CFStringEncoding = 0x020A; +//static kCFStringEncodingISOLatinThai: CFStringEncoding = 0x020B; +//static kCFStringEncodingISOLatin7: CFStringEncoding = 0x020D; +//static kCFStringEncodingISOLatin8: CFStringEncoding = 0x020E; +//static kCFStringEncodingISOLatin9: CFStringEncoding = 0x020F; +//static kCFStringEncodingISOLatin10: CFStringEncoding = 0x0210; +//static kCFStringEncodingDOSLatinUS: CFStringEncoding = 0x0400; +//static kCFStringEncodingDOSGreek: CFStringEncoding = 0x0405; +//static kCFStringEncodingDOSBalticRim: CFStringEncoding = 0x0406; +//static kCFStringEncodingDOSLatin1: CFStringEncoding = 0x0410; +//static kCFStringEncodingDOSGreek1: CFStringEncoding = 0x0411; +//static kCFStringEncodingDOSLatin2: CFStringEncoding = 0x0412; +//static kCFStringEncodingDOSCyrillic: CFStringEncoding = 0x0413; +//static kCFStringEncodingDOSTurkish: CFStringEncoding = 0x0414; +//static kCFStringEncodingDOSPortuguese: CFStringEncoding = 0x0415; +//static kCFStringEncodingDOSIcelandic: CFStringEncoding = 0x0416; +//static kCFStringEncodingDOSHebrew: CFStringEncoding = 0x0417; +//static kCFStringEncodingDOSCanadianFrench: CFStringEncoding = 0x0418; +//static kCFStringEncodingDOSArabic: CFStringEncoding = 0x0419; +//static kCFStringEncodingDOSNordic: CFStringEncoding = 0x041A; +//static kCFStringEncodingDOSRussian: CFStringEncoding = 0x041B; +//static kCFStringEncodingDOSGreek2: CFStringEncoding = 0x041C; +//static kCFStringEncodingDOSThai: CFStringEncoding = 0x041D; +//static kCFStringEncodingDOSJapanese: CFStringEncoding = 0x0420; +//static kCFStringEncodingDOSChineseSimplif: CFStringEncoding = 0x0421; +//static kCFStringEncodingDOSKorean: CFStringEncoding = 0x0422; +//static kCFStringEncodingDOSChineseTrad: CFStringEncoding = 0x0423; +// Defined above: kCFStringEncodingWindowsLatin1 = 0x0500 +//static kCFStringEncodingWindowsLatin2: CFStringEncoding = 0x0501; +//static kCFStringEncodingWindowsCyrillic: CFStringEncoding = 0x0502; +//static kCFStringEncodingWindowsGreek: CFStringEncoding = 0x0503; +//static kCFStringEncodingWindowsLatin5: CFStringEncoding = 0x0504; +//static kCFStringEncodingWindowsHebrew: CFStringEncoding = 0x0505; +//static kCFStringEncodingWindowsArabic: CFStringEncoding = 0x0506; +//static kCFStringEncodingWindowsBalticRim: CFStringEncoding = 0x0507; +//static kCFStringEncodingWindowsVietnamese: CFStringEncoding = 0x0508; +//static kCFStringEncodingWindowsKoreanJohab: CFStringEncoding = 0x0510; +// Defined above: kCFStringEncodingASCII = 0x0600 +//static kCFStringEncodingANSEL: CFStringEncoding = 0x0601; +//static kCFStringEncodingJIS_X0201_76: CFStringEncoding = 0x0620; +//static kCFStringEncodingJIS_X0208_83: CFStringEncoding = 0x0621; +//static kCFStringEncodingJIS_X0208_90: CFStringEncoding = 0x0622; +//static kCFStringEncodingJIS_X0212_90: CFStringEncoding = 0x0623; +//static kCFStringEncodingJIS_C6226_78: CFStringEncoding = 0x0624; +//static kCFStringEncodingShiftJIS_X0213: CFStringEncoding = 0x0628; +//static kCFStringEncodingShiftJIS_X0213_MenKuTen: CFStringEncoding = 0x0629; +//static kCFStringEncodingGB_2312_80: CFStringEncoding = 0x0630; +//static kCFStringEncodingGBK_95: CFStringEncoding = 0x0631; +//static kCFStringEncodingGB_18030_2000: CFStringEncoding = 0x0632; +//static kCFStringEncodingKSC_5601_87: CFStringEncoding = 0x0640; +//static kCFStringEncodingKSC_5601_92_Johab: CFStringEncoding = 0x0641; +//static kCFStringEncodingCNS_11643_92_P1: CFStringEncoding = 0x0651; +//static kCFStringEncodingCNS_11643_92_P2: CFStringEncoding = 0x0652; +//static kCFStringEncodingCNS_11643_92_P3: CFStringEncoding = 0x0653; +//static kCFStringEncodingISO_2022_JP: CFStringEncoding = 0x0820; +//static kCFStringEncodingISO_2022_JP_2: CFStringEncoding = 0x0821; +//static kCFStringEncodingISO_2022_JP_1: CFStringEncoding = 0x0822; +//static kCFStringEncodingISO_2022_JP_3: CFStringEncoding = 0x0823; +//static kCFStringEncodingISO_2022_CN: CFStringEncoding = 0x0830; +//static kCFStringEncodingISO_2022_CN_EXT: CFStringEncoding = 0x0831; +//static kCFStringEncodingISO_2022_KR: CFStringEncoding = 0x0840; +//static kCFStringEncodingEUC_JP: CFStringEncoding = 0x0920; +//static kCFStringEncodingEUC_CN: CFStringEncoding = 0x0930; +//static kCFStringEncodingEUC_TW: CFStringEncoding = 0x0931; +//static kCFStringEncodingEUC_KR: CFStringEncoding = 0x0940; +//static kCFStringEncodingShiftJIS: CFStringEncoding = 0x0A01; +//static kCFStringEncodingKOI8_R: CFStringEncoding = 0x0A02; +//static kCFStringEncodingBig5: CFStringEncoding = 0x0A03; +//static kCFStringEncodingMacRomanLatin1: CFStringEncoding = 0x0A04; +//static kCFStringEncodingHZ_GB_2312: CFStringEncoding = 0x0A05; +//static kCFStringEncodingBig5_HKSCS_1999: CFStringEncoding = 0x0A06; +//static kCFStringEncodingVISCII: CFStringEncoding = 0x0A07; +//static kCFStringEncodingKOI8_U: CFStringEncoding = 0x0A08; +//static kCFStringEncodingBig5_E: CFStringEncoding = 0x0A09; +// Defined above: kCFStringEncodingNextStepLatin = 0x0B01 +//static kCFStringEncodingNextStepJapanese: CFStringEncoding = 0x0B02; +//static kCFStringEncodingEBCDIC_US: CFStringEncoding = 0x0C01; +//static kCFStringEncodingEBCDIC_CP037: CFStringEncoding = 0x0C02; +//static kCFStringEncodingUTF7: CFStringEncoding = 0x04000100; +//static kCFStringEncodingUTF7_IMAP: CFStringEncoding = 0x0A10; +//static kCFStringEncodingShiftJIS_X0213_00: CFStringEncoding = 0x0628; /* Deprecated */ + +#[repr(C)] +pub struct __CFString(c_void); + +pub type CFStringRef = *const __CFString; + +extern { + /* + * CFString.h + */ + + // N.B. organized according to "Functions by task" in docs + + /* Creating a CFString */ + //fn CFSTR + //fn CFStringCreateArrayBySeparatingStrings + //fn CFStringCreateByCombiningStrings + //fn CFStringCreateCopy + //fn CFStringCreateFromExternalRepresentation + pub fn CFStringCreateWithBytes(alloc: CFAllocatorRef, + bytes: *const u8, + numBytes: CFIndex, + encoding: CFStringEncoding, + isExternalRepresentation: Boolean) + -> CFStringRef; + pub fn CFStringCreateWithBytesNoCopy(alloc: CFAllocatorRef, + bytes: *const u8, + numBytes: CFIndex, + encoding: CFStringEncoding, + isExternalRepresentation: Boolean, + contentsDeallocator: CFAllocatorRef) + -> CFStringRef; + //fn CFStringCreateWithCharacters + //fn CFStringCreateWithCharactersNoCopy + pub fn CFStringCreateWithCString(alloc: CFAllocatorRef, + cStr: *const c_char, + encoding: CFStringEncoding) + -> CFStringRef; + //fn CFStringCreateWithCStringNoCopy + //fn CFStringCreateWithFormat + //fn CFStringCreateWithFormatAndArguments + //fn CFStringCreateWithPascalString + //fn CFStringCreateWithPascalStringNoCopy + //fn CFStringCreateWithSubstring + + /* Searching Strings */ + //fn CFStringCreateArrayWithFindResults + //fn CFStringFind + //fn CFStringFindCharacterFromSet + //fn CFStringFindWithOptions + //fn CFStringFindWithOptionsAndLocale + //fn CFStringGetLineBounds + + /* Comparing Strings */ + //fn CFStringCompare + //fn CFStringCompareWithOptions + //fn CFStringCompareWithOptionsAndLocale + //fn CFStringHasPrefix + //fn CFStringHasSuffix + + /* Accessing Characters */ + //fn CFStringCreateExternalRepresentation + pub fn CFStringGetBytes(theString: CFStringRef, + range: CFRange, + encoding: CFStringEncoding, + lossByte: u8, + isExternalRepresentation: Boolean, + buffer: *mut u8, + maxBufLen: CFIndex, + usedBufLen: *mut CFIndex) + -> CFIndex; + //fn CFStringGetCharacterAtIndex + //fn CFStringGetCharacters + //fn CFStringGetCharactersPtr + //fn CFStringGetCharacterFromInlineBuffer + pub fn CFStringGetCString(theString: CFStringRef, + buffer: *mut c_char, + bufferSize: CFIndex, + encoding: CFStringEncoding) + -> Boolean; + pub fn CFStringGetCStringPtr(theString: CFStringRef, + encoding: CFStringEncoding) + -> *const c_char; + pub fn CFStringGetLength(theString: CFStringRef) -> CFIndex; + //fn CFStringGetPascalString + //fn CFStringGetPascalStringPtr + //fn CFStringGetRangeOfComposedCharactersAtIndex + //fn CFStringInitInlineBuffer + + /* Working With Hyphenation */ + //fn CFStringGetHyphenationLocationBeforeIndex + //fn CFStringIsHyphenationAvailableForLocale + + /* Working With Encodings */ + //fn CFStringConvertEncodingToIANACharSetName + //fn CFStringConvertEncodingToNSStringEncoding + //fn CFStringConvertEncodingToWindowsCodepage + //fn CFStringConvertIANACharSetNameToEncoding + //fn CFStringConvertNSStringEncodingToEncoding + //fn CFStringConvertWindowsCodepageToEncoding + //fn CFStringGetFastestEncoding + //fn CFStringGetListOfAvailableEncodings + //fn CFStringGetMaximumSizeForEncoding + //fn CFStringGetMostCompatibleMacStringEncoding + //fn CFStringGetNameOfEncoding + //fn CFStringGetSmallestEncoding + //fn CFStringGetSystemEncoding + //fn CFStringIsEncodingAvailable + + /* Getting Numeric Values */ + //fn CFStringGetDoubleValue + //fn CFStringGetIntValue + + /* Getting String Properties */ + //fn CFShowStr + pub fn CFStringGetTypeID() -> CFTypeID; + + /* String File System Representations */ + //fn CFStringCreateWithFileSystemRepresentation + //fn CFStringGetFileSystemRepresentation + //fn CFStringGetMaximumSizeOfFileSystemRepresentation + + /* Getting Paragraph Bounds */ + //fn CFStringGetParagraphBounds + + /* Managing Surrogates */ + //fn CFStringGetLongCharacterForSurrogatePair + //fn CFStringGetSurrogatePairForLongCharacter + //fn CFStringIsSurrogateHighCharacter + //fn CFStringIsSurrogateLowCharacter +} diff --git a/core-foundation-sys-0.4.6/src/timezone.rs b/core-foundation-sys-0.4.6/src/timezone.rs new file mode 100644 index 000000000..0376974ba --- /dev/null +++ b/core-foundation-sys-0.4.6/src/timezone.rs @@ -0,0 +1,27 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::c_void; + +use base::{CFAllocatorRef, CFTypeID}; +use date::{CFTimeInterval, CFAbsoluteTime}; + +#[repr(C)] +pub struct __CFTimeZone(c_void); + +pub type CFTimeZoneRef = *const __CFTimeZone; + +extern { + pub fn CFTimeZoneCopySystem() -> CFTimeZoneRef; + pub fn CFTimeZoneCopyDefault() -> CFTimeZoneRef; + pub fn CFTimeZoneCreateWithTimeIntervalFromGMT(allocator: CFAllocatorRef, interval: CFTimeInterval) -> CFTimeZoneRef; + pub fn CFTimeZoneGetSecondsFromGMT(tz: CFTimeZoneRef, time: CFAbsoluteTime) -> CFTimeInterval; + + pub fn CFTimeZoneGetTypeID() -> CFTypeID; +} diff --git a/core-foundation-sys-0.4.6/src/url.rs b/core-foundation-sys-0.4.6/src/url.rs new file mode 100644 index 000000000..bb141ad4b --- /dev/null +++ b/core-foundation-sys-0.4.6/src/url.rs @@ -0,0 +1,163 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +use libc::c_void; + +use base::{CFOptionFlags, CFIndex, CFAllocatorRef, Boolean, CFTypeID, CFTypeRef, SInt32}; +use string::{CFStringRef, CFStringEncoding}; +use error::CFErrorRef; + +#[repr(C)] +pub struct __CFURL(c_void); + +pub type CFURLRef = *const __CFURL; + +pub type CFURLBookmarkCreationOptions = CFOptionFlags; + +pub type CFURLPathStyle = CFIndex; + +/* typedef CF_ENUM(CFIndex, CFURLPathStyle) */ +pub const kCFURLPOSIXPathStyle: CFURLPathStyle = 0; +pub const kCFURLHFSPathStyle: CFURLPathStyle = 1; +pub const kCFURLWindowsPathStyle: CFURLPathStyle = 2; + +// static kCFURLBookmarkCreationPreferFileIDResolutionMask: CFURLBookmarkCreationOptions = +// (1 << 8) as u32; +// static kCFURLBookmarkCreationMinimalBookmarkMask: CFURLBookmarkCreationOptions = +// (1 << 9) as u32; +// static kCFURLBookmarkCreationSuitableForBookmarkFile: CFURLBookmarkCreationOptions = +// (1 << 10) as u32; +// static kCFURLBookmarkCreationWithSecurityScope: CFURLBookmarkCreationOptions = +// (1 << 11) as u32; +// static kCFURLBookmarkCreationSecurityScopeAllowOnlyReadAccess: CFURLBookmarkCreationOptions = +// (1 << 12) as u32; + +// TODO: there are a lot of missing keys and constants. Add if you are bored or need them. + +extern { + /* + * CFURL.h + */ + + /* Common File System Resource Keys */ + pub static kCFURLAttributeModificationDateKey: CFStringRef; + pub static kCFURLContentAccessDateKey: CFStringRef; + pub static kCFURLContentModificationDateKey: CFStringRef; + pub static kCFURLCreationDateKey: CFStringRef; + pub static kCFURLFileResourceIdentifierKey: CFStringRef; + pub static kCFURLFileSecurityKey: CFStringRef; + pub static kCFURLHasHiddenExtensionKey: CFStringRef; + pub static kCFURLIsDirectoryKey: CFStringRef; + pub static kCFURLIsExecutableKey: CFStringRef; + pub static kCFURLIsHiddenKey: CFStringRef; + pub static kCFURLIsPackageKey: CFStringRef; + pub static kCFURLIsReadableKey: CFStringRef; + pub static kCFURLIsRegularFileKey: CFStringRef; + pub static kCFURLIsSymbolicLinkKey: CFStringRef; + pub static kCFURLIsSystemImmutableKey: CFStringRef; + pub static kCFURLIsUserImmutableKey: CFStringRef; + pub static kCFURLIsVolumeKey: CFStringRef; + pub static kCFURLIsWritableKey: CFStringRef; + pub static kCFURLLabelNumberKey: CFStringRef; + pub static kCFURLLinkCountKey: CFStringRef; + pub static kCFURLLocalizedLabelKey: CFStringRef; + pub static kCFURLLocalizedNameKey: CFStringRef; + pub static kCFURLLocalizedTypeDescriptionKey: CFStringRef; + pub static kCFURLNameKey: CFStringRef; + pub static kCFURLParentDirectoryURLKey: CFStringRef; + pub static kCFURLPreferredIOBlockSizeKey: CFStringRef; + pub static kCFURLTypeIdentifierKey: CFStringRef; + pub static kCFURLVolumeIdentifierKey: CFStringRef; + pub static kCFURLVolumeURLKey: CFStringRef; + + #[cfg(feature="mac_os_10_8_features")] + #[cfg_attr(feature = "mac_os_10_7_support", linkage = "extern_weak")] + pub static kCFURLIsExcludedFromBackupKey: CFStringRef; + pub static kCFURLFileResourceTypeKey: CFStringRef; + + /* Creating a CFURL */ + pub fn CFURLCopyAbsoluteURL(anURL: CFURLRef) -> CFURLRef; + //fn CFURLCreateAbsoluteURLWithBytes + //fn CFURLCreateByResolvingBookmarkData + //fn CFURLCreateCopyAppendingPathComponent + //fn CFURLCreateCopyAppendingPathExtension + //fn CFURLCreateCopyDeletingLastPathComponent + //fn CFURLCreateCopyDeletingPathExtension + pub fn CFURLCreateFilePathURL(allocator: CFAllocatorRef, url: CFURLRef, error: *mut CFErrorRef) -> CFURLRef; + //fn CFURLCreateFileReferenceURL + pub fn CFURLCreateFromFileSystemRepresentation(allocator: CFAllocatorRef, buffer: *const u8, bufLen: CFIndex, isDirectory: Boolean) -> CFURLRef; + //fn CFURLCreateFromFileSystemRepresentationRelativeToBase + //fn CFURLCreateFromFSRef + pub fn CFURLCreateWithBytes(allocator: CFAllocatorRef, URLBytes: *const u8, length: CFIndex, encoding: CFStringEncoding, baseURL: CFURLRef) -> CFURLRef; + pub fn CFURLCreateWithFileSystemPath(allocator: CFAllocatorRef, filePath: CFStringRef, pathStyle: CFURLPathStyle, isDirectory: Boolean) -> CFURLRef; + pub fn CFURLCreateWithFileSystemPathRelativeToBase(allocator: CFAllocatorRef, filePath: CFStringRef, pathStyle: CFURLPathStyle, isDirectory: Boolean, baseURL: CFURLRef) -> CFURLRef; + //fn CFURLCreateWithString(allocator: CFAllocatorRef, urlString: CFStringRef, + // baseURL: CFURLRef) -> CFURLRef; + + /* Accessing the Parts of a URL */ + pub fn CFURLCanBeDecomposed(anURL: CFURLRef) -> Boolean; + pub fn CFURLCopyFileSystemPath(anURL: CFURLRef, pathStyle: CFURLPathStyle) -> CFStringRef; + pub fn CFURLCopyFragment(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) -> CFStringRef; + pub fn CFURLCopyHostName(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyLastPathComponent(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyNetLocation(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyParameterString(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) -> CFStringRef; + pub fn CFURLCopyPassword(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyPath(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyPathExtension(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyQueryString(anURL: CFURLRef, charactersToLeaveEscaped: CFStringRef) -> CFStringRef; + pub fn CFURLCopyResourceSpecifier(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyScheme(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLCopyStrictPath(anURL: CFURLRef, isAbsolute: *mut Boolean) -> CFStringRef; + pub fn CFURLCopyUserName(anURL: CFURLRef) -> CFStringRef; + pub fn CFURLGetPortNumber(anURL: CFURLRef) -> SInt32; + pub fn CFURLHasDirectoryPath(anURL: CFURLRef) -> Boolean; + + /* Converting URLs to Other Representations */ + //fn CFURLCreateData(allocator: CFAllocatorRef, url: CFURLRef, + // encoding: CFStringEncoding, escapeWhitespace: bool) -> CFDataRef; + //fn CFURLCreateStringByAddingPercentEscapes + //fn CFURLCreateStringByReplacingPercentEscapes + //fn CFURLCreateStringByReplacingPercentEscapesUsingEncoding + pub fn CFURLGetFileSystemRepresentation(anURL: CFURLRef, resolveAgainstBase: Boolean, buffer: *mut u8, maxBufLen: CFIndex) -> Boolean; + + //fn CFURLGetFSRef + pub fn CFURLGetString(anURL: CFURLRef) -> CFStringRef; + + /* Getting URL Properties */ + //fn CFURLGetBaseURL(anURL: CFURLRef) -> CFURLRef; + pub fn CFURLGetBytes(anURL: CFURLRef, buffer: *mut u8, bufferLength: CFIndex) -> CFIndex; + //fn CFURLGetByteRangeForComponent + pub fn CFURLGetTypeID() -> CFTypeID; + //fn CFURLResourceIsReachable + + /* Getting and Setting File System Resource Properties */ + pub fn CFURLClearResourcePropertyCache(url: CFURLRef); + //fn CFURLClearResourcePropertyCacheForKey + //fn CFURLCopyResourcePropertiesForKeys + //fn CFURLCopyResourcePropertyForKey + //fn CFURLCreateResourcePropertiesForKeysFromBookmarkData + //fn CFURLCreateResourcePropertyForKeyFromBookmarkData + //fn CFURLSetResourcePropertiesForKeys + pub fn CFURLSetResourcePropertyForKey(url: CFURLRef, key: CFStringRef, value: CFTypeRef, error: *mut CFErrorRef) -> Boolean; + //fn CFURLSetTemporaryResourcePropertyForKey + + /* Working with Bookmark Data */ + //fn CFURLCreateBookmarkData + //fn CFURLCreateBookmarkDataFromAliasRecord + //fn CFURLCreateBookmarkDataFromFile + //fn CFURLWriteBookmarkDataToFile + //fn CFURLStartAccessingSecurityScopedResource + //fn CFURLStopAccessingSecurityScopedResource +} + +#[test] +#[cfg(feature="mac_os_10_8_features")] +fn can_see_excluded_from_backup_key() { + let _ = unsafe { kCFURLIsExcludedFromBackupKey }; +} diff --git a/core-foundation-sys-0.4.6/src/uuid.rs b/core-foundation-sys-0.4.6/src/uuid.rs new file mode 100644 index 000000000..63c180fa1 --- /dev/null +++ b/core-foundation-sys-0.4.6/src/uuid.rs @@ -0,0 +1,48 @@ +// Copyright 2013-2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +use libc::c_void; + +use base::{CFAllocatorRef, CFTypeID}; + +#[repr(C)] +pub struct __CFUUID(c_void); + +pub type CFUUIDRef = *const __CFUUID; + +#[repr(C)] +#[derive(Clone, Copy, Default)] +pub struct CFUUIDBytes { + pub byte0: u8, + pub byte1: u8, + pub byte2: u8, + pub byte3: u8, + pub byte4: u8, + pub byte5: u8, + pub byte6: u8, + pub byte7: u8, + pub byte8: u8, + pub byte9: u8, + pub byte10: u8, + pub byte11: u8, + pub byte12: u8, + pub byte13: u8, + pub byte14: u8, + pub byte15: u8 +} + +extern { + /* + * CFUUID.h + */ + pub fn CFUUIDCreate(allocator: CFAllocatorRef) -> CFUUIDRef; + pub fn CFUUIDCreateFromUUIDBytes(allocator: CFAllocatorRef, bytes: CFUUIDBytes) -> CFUUIDRef; + pub fn CFUUIDGetUUIDBytes(uuid: CFUUIDRef) -> CFUUIDBytes; + + pub fn CFUUIDGetTypeID() -> CFTypeID; +} diff --git a/crossbeam-0.2.12/.cargo-checksum.json b/crossbeam-0.2.12/.cargo-checksum.json new file mode 100644 index 000000000..5c0c59cc5 --- /dev/null +++ b/crossbeam-0.2.12/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be"} \ No newline at end of file diff --git a/crossbeam-0.2.12/.travis.yml b/crossbeam-0.2.12/.travis.yml new file mode 100644 index 000000000..7e692baaf --- /dev/null +++ b/crossbeam-0.2.12/.travis.yml @@ -0,0 +1,36 @@ +language: rust +# necessary for `travis-cargo coveralls --no-sudo` +addons: + apt: + packages: + - libcurl4-openssl-dev + - libelf-dev + - libdw-dev + +# run builds for all the trains (and more) +rust: + - nightly + - beta + - stable + +# load travis-cargo +before_script: + - | + pip install 'travis-cargo<0.2' --user && + export PATH=$HOME/.local/bin:$PATH + +# the main build +script: + - | + travis-cargo build && + travis-cargo test && + travis-cargo test -- --release && + travis-cargo run -- --bin bench --release && + travis-cargo --only stable doc +env: + global: + # override the default `--features unstable` used for the nightly branch (optional) + - TRAVIS_CARGO_NIGHTLY_FEATURE=nightly +notifications: + email: + on_success: never diff --git a/crossbeam-0.2.12/CHANGELOG.md b/crossbeam-0.2.12/CHANGELOG.md new file mode 100644 index 000000000..b80782113 --- /dev/null +++ b/crossbeam-0.2.12/CHANGELOG.md @@ -0,0 +1,11 @@ +# Version 0.2 + +- Changed existing non-blocking `pop` methods to `try_pop` +- Added blocking `pop` support to Michael-Scott queue +- Added Chase-Lev work-stealing deque + +# Version 0.1 + +- Added [epoch-based memory management](http://aturon.github.io/blog/2015/08/27/epoch/) +- Added Michael-Scott queue +- Added Segmented array queue diff --git a/crossbeam-0.2.12/Cargo.toml b/crossbeam-0.2.12/Cargo.toml new file mode 100644 index 000000000..64debfc1e --- /dev/null +++ b/crossbeam-0.2.12/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "crossbeam" +version = "0.2.12" +authors = ["Aaron Turon "] +description = "Support for lock-free data structures, synchronizers, and parallel programming" +documentation = "http://aturon.github.io/crossbeam-doc/crossbeam/" +readme = "README.md" +license = "Apache-2.0/MIT" +repository = "https://github.com/aturon/crossbeam" +[dev-dependencies.rand] +version = "0.3" + +[features] +nightly = [] diff --git a/crossbeam-0.2.12/LICENSE-APACHE b/crossbeam-0.2.12/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/crossbeam-0.2.12/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/crossbeam-0.2.12/LICENSE-MIT b/crossbeam-0.2.12/LICENSE-MIT new file mode 100644 index 000000000..e69282e38 --- /dev/null +++ b/crossbeam-0.2.12/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/crossbeam-0.2.12/README.md b/crossbeam-0.2.12/README.md new file mode 100644 index 000000000..47d666c2a --- /dev/null +++ b/crossbeam-0.2.12/README.md @@ -0,0 +1,38 @@ +# Crossbeam: support for concurrent and parallel programming + +[![Build Status](https://travis-ci.org/aturon/crossbeam.svg?branch=master)](https://travis-ci.org/aturon/crossbeam) + +This crate is an early work in progress. The focus for the moment is +concurrency: + +- **Non-blocking data structures**. These data structures allow for high +performance, highly-concurrent access, much superior to wrapping with a +`Mutex`. Ultimately the goal is to include stacks, queues, deques, bags, sets +and maps. + +- **Memory management**. Because non-blocking data structures avoid global +synchronization, it is not easy to tell when internal data can be safely +freed. The `mem` module provides generic, easy to use, and high-performance APIs +for managing memory in these cases. + +- **Synchronization**. The standard library provides a few synchronization +primitives (locks, semaphores, barriers, etc) but this crate seeks to expand +that set to include more advanced/niche primitives, as well as userspace +alternatives. + +- **Scoped thread API**. Finally, the crate provides a "scoped" thread API, +making it possible to spawn threads that share stack data with their parents. + +# Usage + +To use Crossbeam, add this to your `Cargo.toml`: + +```toml +[dependencies] +crossbeam = "0.2" +``` + +For examples of what Crossbeam is capable of, see the +[documentation][docs]. + +[docs]: http://aturon.github.io/crossbeam-doc/crossbeam/ diff --git a/crossbeam-0.2.12/scala-bench/bench.scala b/crossbeam-0.2.12/scala-bench/bench.scala new file mode 100644 index 000000000..5661b23e3 --- /dev/null +++ b/crossbeam-0.2.12/scala-bench/bench.scala @@ -0,0 +1,195 @@ +import scala.concurrent.ExecutionContext.Implicits.global +import scala.concurrent._ +import scala.concurrent.duration._ +import java.util.concurrent.ConcurrentLinkedQueue +import java.util.concurrent.atomic._ +import java.util.Stack + +import scala.annotation.tailrec + +final class MSQueue[A](a: A) { + private abstract class Q + private final case class Node(data: A, next: AtomicReference[Q] = new AtomicReference(Emp)) extends Q + private final case object Emp extends Q + private val head = new AtomicReference(Node(a)) + private val tail = new AtomicReference(head.get()) + + def enq(a: A) { + val newNode = new Node(a) + while (true) { + val curTail = tail.get() + curTail.next.get()match { + case n@Node(_,_) => tail.compareAndSet(curTail, n) + case Emp => { + if (curTail.next.compareAndSet(Emp, newNode)) { + tail.compareAndSet(curTail, newNode) + return + } + } + } + } + } + + def deq(): Option[A] = { + while (true) { + val cur_head = head.get() + cur_head.next.get() match { + case Emp => return None + case n@Node(data, _) => { + if (head.compareAndSet(cur_head, n)) { + return Some(data) + } + } + } + } + None + } +} + +abstract class MyBool +final case class MyTrue() extends MyBool +final case class MyFalse() extends MyBool + +object Bench { + def time(block: => Unit): Long = { + val t0 = System.nanoTime() + val result = block // call-by-name + val t1 = System.nanoTime() + t1 - t0 + } + + def do_linked(threads: Int, count: Int) { + val q: ConcurrentLinkedQueue[MyBool] = new ConcurrentLinkedQueue(); + + val t = time { + var s = new Stack[Future[Unit]] + for (i <- 1 to threads) { + s.push(Future { + for (i <- 1 to count+1) { + //if (i % 100000 == 0) { println(q.size()) } + q.offer(MyTrue()) + } + }) + } + + var rn = 0 + while (rn < count) { + if (q.poll() != null) { + rn += 1 + } + } + + while (!s.empty()) { + Await.ready(s.pop(), Duration.Inf) + } + } + + println("Linked: " + t / (count * threads)) + } + + def do_linked_mpmc(threads: Int, count: Int) { + val q = new ConcurrentLinkedQueue[MyBool]; + val prod = new AtomicInteger(); + + val t = time { + var s = new Stack[Future[Unit]] + for (i <- 1 to threads) { + s.push(Future { + for (i <- 1 to count+1) { + q.offer(MyTrue()) + //if (i % 100000 == 0) { println(q.size()) } + } + if (prod.incrementAndGet() == threads) { + for (i <- 0 to threads) { q.offer(MyFalse()) } + } + }) + s.push(Future { + var done = false; + while (!done) { + q.poll() match { + case MyFalse() => done = true + case _ => {} + } + } + }) + } + + while (!s.empty()) { + Await.ready(s.pop(), Duration.Inf) + } + } + + println("Linked mpmc: " + t / (count * threads) + " (" + t / 1000000000 + ")") + } + + + def do_msq(threads: Int, count: Int) { + val q = new MSQueue[Int](0); + + val t = time { + var s = new Stack[Future[Unit]] + for (i <- 1 to threads) { + s.push(Future { for (i <- 1 to count+1) { q.enq(i) } }) + } + + var rn = 0 + while (rn < count) { + if (q.deq() != None) { + rn += 1 + } + } + + while (!s.empty()) { + Await.ready(s.pop(), Duration.Inf) + } + } + + println("MSQ: " + t / (count * threads) + " (" + t / 1000000000 + ")") + } + + def do_msq_mpmc(threads: Int, count: Int) { + val q = new MSQueue[Boolean](true); + val prod = new AtomicInteger(); + + val t = time { + var s = new Stack[Future[Unit]] + for (i <- 1 to threads) { + s.push(Future { + for (i <- 1 to count+1) { q.enq(true) } + if (prod.incrementAndGet() == threads) { + for (i <- 1 to threads) { q.enq(false) } + } + }) + s.push(Future { + var done = false; + while (!done) { + q.deq() match { + case Some(false) => done = true + case _ => {} + } + } + }) + } + + while (!s.empty()) { + Await.ready(s.pop(), Duration.Inf) + } + } + + println("MSQ mpmc: " + t / (count * threads) + " (" + t / 1000000000 + ")") + } + + def main(args: Array[String]) { + do_linked(2, 1000000) + do_linked(2, 10000000) + + do_msq(2, 1000000) + do_msq(2, 10000000) + + do_linked_mpmc(2, 1000000) + do_linked_mpmc(2, 10000000) + + do_msq_mpmc(2, 1000000) + do_msq_mpmc(2, 10000000) + } +} diff --git a/crossbeam-0.2.12/src/bin/bench.rs b/crossbeam-0.2.12/src/bin/bench.rs new file mode 100755 index 000000000..f233d5ab2 --- /dev/null +++ b/crossbeam-0.2.12/src/bin/bench.rs @@ -0,0 +1,165 @@ +extern crate crossbeam; + +use std::collections::VecDeque; +use std::sync::Mutex; +use std::sync::mpsc::channel; +use std::time::Duration; + +use crossbeam::scope; +use crossbeam::sync::MsQueue; +use crossbeam::sync::SegQueue; + +use extra_impls::mpsc_queue::Queue as MpscQueue; + +mod extra_impls; + +const COUNT: u64 = 10000000; +const THREADS: u64 = 2; + +#[cfg(feature = "nightly")] +fn time(f: F) -> Duration { + let start = ::std::time::Instant::now(); + f(); + start.elapsed() +} + +#[cfg(not(feature = "nightly"))] +fn time(_f: F) -> Duration { + Duration::new(0, 0) +} + +fn nanos(d: Duration) -> f64 { + d.as_secs() as f64 * 1000000000f64 + (d.subsec_nanos() as f64) +} + +trait Queue { + fn push(&self, T); + fn try_pop(&self) -> Option; +} + +impl Queue for MsQueue { + fn push(&self, t: T) { self.push(t) } + fn try_pop(&self) -> Option { self.try_pop() } +} + +impl Queue for SegQueue { + fn push(&self, t: T) { self.push(t) } + fn try_pop(&self) -> Option { self.try_pop() } +} + +impl Queue for MpscQueue { + fn push(&self, t: T) { self.push(t) } + fn try_pop(&self) -> Option { + use extra_impls::mpsc_queue::*; + + loop { + match self.pop() { + Data(t) => return Some(t), + Empty => return None, + Inconsistent => (), + } + } + } +} + +impl Queue for Mutex> { + fn push(&self, t: T) { self.lock().unwrap().push_back(t) } + fn try_pop(&self) -> Option { self.lock().unwrap().pop_front() } +} + +fn bench_queue_mpsc + Sync>(q: Q) -> f64 { + let d = time(|| { + scope(|scope| { + for _i in 0..THREADS { + let qr = &q; + scope.spawn(move || { + for x in 0..COUNT { + let _ = qr.push(x); + } + }); + } + + let mut count = 0; + while count < COUNT*THREADS { + if q.try_pop().is_some() { + count += 1; + } + } + }); + }); + + nanos(d) / ((COUNT * THREADS) as f64) +} + +fn bench_queue_mpmc + Sync>(q: Q) -> f64 { + use std::sync::atomic::AtomicUsize; + use std::sync::atomic::Ordering::Relaxed; + + let prod_count = AtomicUsize::new(0); + + let d = time(|| { + scope(|scope| { + for _i in 0..THREADS { + let qr = &q; + let pcr = &prod_count; + scope.spawn(move || { + for _x in 0..COUNT { + qr.push(true); + } + if pcr.fetch_add(1, Relaxed) == (THREADS as usize) - 1 { + for _x in 0..THREADS { + qr.push(false) + } + } + }); + scope.spawn(move || { + loop { + if let Some(false) = qr.try_pop() { break } + } + }); + } + + + }); + }); + + nanos(d) / ((COUNT * THREADS) as f64) +} + +fn bench_chan_mpsc() -> f64 { + let (tx, rx) = channel(); + + let d = time(|| { + scope(|scope| { + for _i in 0..THREADS { + let my_tx = tx.clone(); + + scope.spawn(move || { + for x in 0..COUNT { + let _ = my_tx.send(x); + } + }); + } + + for _i in 0..COUNT*THREADS { + let _ = rx.recv().unwrap(); + } + }); + }); + + nanos(d) / ((COUNT * THREADS) as f64) +} + +fn main() { + println!("MSQ mpsc: {}", bench_queue_mpsc(MsQueue::new())); + println!("chan mpsc: {}", bench_chan_mpsc()); + println!("mpsc mpsc: {}", bench_queue_mpsc(MpscQueue::new())); + println!("Seg mpsc: {}", bench_queue_mpsc(SegQueue::new())); + + println!("MSQ mpmc: {}", bench_queue_mpmc(MsQueue::new())); + println!("Seg mpmc: {}", bench_queue_mpmc(SegQueue::new())); + +// println!("queue_mpsc: {}", bench_queue_mpsc()); +// println!("queue_mpmc: {}", bench_queue_mpmc()); +// println!("mutex_mpmc: {}", bench_mutex_mpmc()); +} diff --git a/crossbeam-0.2.12/src/bin/extra_impls/mod.rs b/crossbeam-0.2.12/src/bin/extra_impls/mod.rs new file mode 100644 index 000000000..485946a9f --- /dev/null +++ b/crossbeam-0.2.12/src/bin/extra_impls/mod.rs @@ -0,0 +1 @@ +pub mod mpsc_queue; diff --git a/crossbeam-0.2.12/src/bin/extra_impls/mpsc_queue.rs b/crossbeam-0.2.12/src/bin/extra_impls/mpsc_queue.rs new file mode 100644 index 000000000..3bff5dc6c --- /dev/null +++ b/crossbeam-0.2.12/src/bin/extra_impls/mpsc_queue.rs @@ -0,0 +1,155 @@ +/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Dmitry Vyukov. + */ + +//! A mostly lock-free multi-producer, single consumer queue. +//! +//! This module contains an implementation of a concurrent MPSC queue. This +//! queue can be used to share data between threads, and is also used as the +//! building block of channels in rust. +//! +//! Note that the current implementation of this queue has a caveat of the `pop` +//! method, and see the method for more information about it. Due to this +//! caveat, this queue may not be appropriate for all use-cases. + +// http://www.1024cores.net/home/lock-free-algorithms +// /queues/non-intrusive-mpsc-node-based-queue + +pub use self::PopResult::*; + +use std::fmt; +use std::ptr; +use std::cell::UnsafeCell; + +use std::sync::atomic::{AtomicPtr, Ordering}; + +/// A result of the `pop` function. +#[derive(Debug)] +pub enum PopResult { + /// Some data has been popped + Data(T), + /// The queue is empty + Empty, + /// The queue is in an inconsistent state. Popping data should succeed, but + /// some pushers have yet to make enough progress in order allow a pop to + /// succeed. It is recommended that a pop() occur "in the near future" in + /// order to see if the sender has made progress or not + Inconsistent, +} + +#[derive(Debug)] +struct Node { + next: AtomicPtr>, + value: Option, +} + +/// The multi-producer single-consumer structure. This is not cloneable, but it +/// may be safely shared so long as it is guaranteed that there is only one +/// popper at a time (many pushers are allowed). +pub struct Queue { + head: AtomicPtr>, + tail: UnsafeCell<*mut Node>, +} + +impl fmt::Debug for Queue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Queue {{ ... }}") + } +} + +unsafe impl Send for Queue { } +unsafe impl Sync for Queue { } + +impl Node { + unsafe fn new(v: Option) -> *mut Node { + Box::into_raw(Box::new(Node { + next: AtomicPtr::new(ptr::null_mut()), + value: v, + })) + } +} + +impl Queue { + /// Creates a new queue that is safe to share among multiple producers and + /// one consumer. + pub fn new() -> Queue { + let stub = unsafe { Node::new(None) }; + Queue { + head: AtomicPtr::new(stub), + tail: UnsafeCell::new(stub), + } + } + + /// Pushes a new value onto this queue. + pub fn push(&self, t: T) { + unsafe { + let n = Node::new(Some(t)); + let prev = self.head.swap(n, Ordering::AcqRel); + (*prev).next.store(n, Ordering::Release); + } + } + + /// Pops some data from this queue. + /// + /// Note that the current implementation means that this function cannot + /// return `Option`. It is possible for this queue to be in an + /// inconsistent state where many pushes have succeeded and completely + /// finished, but pops cannot return `Some(t)`. This inconsistent state + /// happens when a pusher is pre-empted at an inopportune moment. + /// + /// This inconsistent state means that this queue does indeed have data, but + /// it does not currently have access to it at this time. + pub fn pop(&self) -> PopResult { + unsafe { + let tail = *self.tail.get(); + let next = (*tail).next.load(Ordering::Acquire); + + if !next.is_null() { + *self.tail.get() = next; + assert!((*tail).value.is_none()); + assert!((*next).value.is_some()); + let ret = (*next).value.take().unwrap(); + let _ = Box::from_raw(tail); + return Data(ret); + } + + if self.head.load(Ordering::Acquire) == tail {Empty} else {Inconsistent} + } + } +} + +impl Drop for Queue { + fn drop(&mut self) { + unsafe { + let mut cur = *self.tail.get(); + while !cur.is_null() { + let next = (*cur).next.load(Ordering::Relaxed); + let _ = Box::from_raw(cur); + cur = next; + } + } + } +} diff --git a/crossbeam-0.2.12/src/bin/stress-msq.rs b/crossbeam-0.2.12/src/bin/stress-msq.rs new file mode 100644 index 000000000..7de749642 --- /dev/null +++ b/crossbeam-0.2.12/src/bin/stress-msq.rs @@ -0,0 +1,36 @@ +extern crate crossbeam; + +use crossbeam::sync::MsQueue; +use crossbeam::scope; + +use std::sync::Arc; + +const DUP: usize = 4; +const THREADS: u32 = 2; +const COUNT: u64 = 100000; + +fn main() { + scope(|s| { + for _i in 0..DUP { + let q = Arc::new(MsQueue::new()); + let qs = q.clone(); + + s.spawn(move || { + for i in 1..COUNT { qs.push(i) } + }); + + for _i in 0..THREADS { + let qr = q.clone(); + s.spawn(move || { + let mut cur: u64 = 0; + for _j in 0..COUNT { + if let Some(new) = qr.try_pop() { + assert!(new > cur); + cur = new; + } + } + }); + } + } + }); +} diff --git a/crossbeam-0.2.12/src/lib.rs b/crossbeam-0.2.12/src/lib.rs new file mode 100644 index 000000000..af69acd6c --- /dev/null +++ b/crossbeam-0.2.12/src/lib.rs @@ -0,0 +1,54 @@ +//! Support for concurrent and parallel programming. +//! +//! This crate is an early work in progress. The focus for the moment is +//! concurrency: +//! +//! - **Non-blocking data structures**. These data structures allow for high +//! performance, highly-concurrent access, much superior to wrapping with a +//! `Mutex`. Ultimately the goal is to include stacks, queues, deques, bags, +//! sets and maps. These live in the `sync` module. +//! +//! - **Memory management**. Because non-blocking data structures avoid global +//! synchronization, it is not easy to tell when internal data can be safely +//! freed. The `mem` module provides generic, easy to use, and high-performance +//! APIs for managing memory in these cases. These live in the `mem` module. +//! +//! - **Synchronization**. The standard library provides a few synchronization +//! primitives (locks, semaphores, barriers, etc) but this crate seeks to expand +//! that set to include more advanced/niche primitives, as well as userspace +//! alternatives. These live in the `sync` module. +//! +//! - **Scoped thread API**. Finally, the crate provides a "scoped" thread API, +//! making it possible to spawn threads that share stack data with their +//! parents. This functionality is exported at the top-level. + +//#![deny(missing_docs)] + +#![cfg_attr(feature = "nightly", + feature(const_fn, repr_simd, optin_builtin_traits))] + +use std::thread; + +pub use scoped::{scope, Scope, ScopedJoinHandle}; + +pub mod mem; +pub mod sync; +mod scoped; + +#[doc(hidden)] +trait FnBox { + fn call_box(self: Box); +} + +impl FnBox for F { + fn call_box(self: Box) { (*self)() } +} + +/// Like `std::thread::spawn`, but without the closure bounds. +pub unsafe fn spawn_unsafe<'a, F>(f: F) -> thread::JoinHandle<()> where F: FnOnce() + Send + 'a { + use std::mem; + + let closure: Box = Box::new(f); + let closure: Box = mem::transmute(closure); + thread::spawn(move || closure.call_box()) +} diff --git a/crossbeam-0.2.12/src/mem/cache_padded.rs b/crossbeam-0.2.12/src/mem/cache_padded.rs new file mode 100644 index 000000000..ae6a3c58e --- /dev/null +++ b/crossbeam-0.2.12/src/mem/cache_padded.rs @@ -0,0 +1,164 @@ +use std::marker; +use std::cell::UnsafeCell; +use std::fmt; +use std::mem; +use std::ptr; +use std::ops::{Deref, DerefMut}; + +// For now, treat this as an arch-independent constant. +const CACHE_LINE: usize = 32; + +#[cfg_attr(feature = "nightly", + repr(simd))] +#[derive(Debug)] +struct Padding(u64, u64, u64, u64); + +/// Pad `T` to the length of a cacheline. +/// +/// Sometimes concurrent programming requires a piece of data to be padded out +/// to the size of a cacheline to avoid "false sharing": cachelines being +/// invalidated due to unrelated concurrent activity. Use the `CachePadded` type +/// when you want to *avoid* cache locality. +/// +/// At the moment, cache lines are assumed to be 32 * sizeof(usize) on all +/// architectures. +/// +/// **Warning**: the wrapped data is never dropped; move out using `ptr::read` +/// if you need to run dtors. +pub struct CachePadded { + data: UnsafeCell<[usize; CACHE_LINE]>, + _marker: ([Padding; 0], marker::PhantomData), +} + +impl fmt::Debug for CachePadded { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "CachePadded {{ ... }}") + } +} + +unsafe impl Send for CachePadded {} +unsafe impl Sync for CachePadded {} + +#[cfg(not(feature = "nightly"))] +macro_rules! declare_zeros_valid { + () => { + /// Types for which mem::zeroed() is safe. + /// + /// If a type `T: ZerosValid`, then a sequence of zeros the size of `T` must be + /// a valid member of the type `T`. + pub unsafe trait ZerosValid {} + } +} + +#[cfg(feature = "nightly")] +macro_rules! declare_zeros_valid { + () => { + /// Types for which mem::zeroed() is safe. + /// + /// If a type `T: ZerosValid`, then a sequence of zeros the size of `T` must be + /// a valid member of the type `T`. + pub unsafe auto trait ZerosValid {} + } +} + +declare_zeros_valid!(); + +macro_rules! zeros_valid { ($( $T:ty )*) => ($( + unsafe impl ZerosValid for $T {} +)*)} + +zeros_valid!(u8 u16 u32 u64 usize); +zeros_valid!(i8 i16 i32 i64 isize); + +unsafe impl ZerosValid for ::std::sync::atomic::AtomicUsize {} +unsafe impl ZerosValid for ::std::sync::atomic::AtomicPtr {} + +impl CachePadded { + /// A const fn equivalent to mem::zeroed(). + #[cfg(not(feature = "nightly"))] + pub fn zeroed() -> CachePadded { + CachePadded { + data: UnsafeCell::new(([0; CACHE_LINE])), + _marker: ([], marker::PhantomData), + } + } + + /// A const fn equivalent to mem::zeroed(). + #[cfg(feature = "nightly")] + pub const fn zeroed() -> CachePadded { + CachePadded { + data: UnsafeCell::new(([0; CACHE_LINE])), + _marker: ([], marker::PhantomData), + } + } +} + +#[inline] +/// Assert that the size and alignment of `T` are consistent with `CachePadded`. +fn assert_valid() { + assert!(mem::size_of::() <= mem::size_of::>()); + assert!(mem::align_of::() <= mem::align_of::>()); +} + +impl CachePadded { + /// Wrap `t` with cacheline padding. + /// + /// **Warning**: the wrapped data is never dropped; move out using + /// `ptr:read` if you need to run dtors. + pub fn new(t: T) -> CachePadded { + assert_valid::(); + let ret = CachePadded { + data: UnsafeCell::new(([0; CACHE_LINE])), + _marker: ([], marker::PhantomData), + }; + unsafe { + let p: *mut T = mem::transmute(&ret.data); + ptr::write(p, t); + } + ret + } +} + +impl Deref for CachePadded { + type Target = T; + fn deref(&self) -> &T { + assert_valid::(); + unsafe { mem::transmute(&self.data) } + } +} + +impl DerefMut for CachePadded { + fn deref_mut(&mut self) -> &mut T { + assert_valid::(); + unsafe { mem::transmute(&mut self.data) } + } +} + +// FIXME: support Drop by pulling out a version usable for statics +/* +impl Drop for CachePadded { + fn drop(&mut self) { + assert_valid::(); + let p: *mut T = mem::transmute(&self.data); + mem::drop(ptr::read(p)); + } +} +*/ + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn cache_padded_store_u64() { + let x: CachePadded = CachePadded::new(17); + assert_eq!(*x, 17); + } + + #[test] + fn cache_padded_store_pair() { + let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37)); + assert_eq!(x.0, 17); + assert_eq!(x.1, 37); + } +} diff --git a/crossbeam-0.2.12/src/mem/epoch/atomic.rs b/crossbeam-0.2.12/src/mem/epoch/atomic.rs new file mode 100644 index 000000000..1d8e7cec5 --- /dev/null +++ b/crossbeam-0.2.12/src/mem/epoch/atomic.rs @@ -0,0 +1,181 @@ +use std::marker::PhantomData; +use std::mem; +use std::ptr; +use std::sync::atomic::{self, Ordering}; + +use super::{Owned, Shared, Guard}; + +/// Like `std::sync::atomic::AtomicPtr`. +/// +/// Provides atomic access to a (nullable) pointer of type `T`, interfacing with +/// the `Owned` and `Shared` types. +#[derive(Debug)] +pub struct Atomic { + ptr: atomic::AtomicPtr, + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for Atomic {} +unsafe impl Sync for Atomic {} + +fn opt_shared_into_raw(val: Option>) -> *mut T { + val.map(|p| p.as_raw()).unwrap_or(ptr::null_mut()) +} + +fn opt_owned_as_raw(val: &Option>) -> *mut T { + val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut()) +} + +fn opt_owned_into_raw(val: Option>) -> *mut T { + let ptr = val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut()); + mem::forget(val); + ptr +} + +impl Atomic { + /// Create a new, null atomic pointer. + #[cfg(feature = "nightly")] + pub const fn null() -> Atomic { + Atomic { + ptr: atomic::AtomicPtr::new(0 as *mut _), + _marker: PhantomData + } + } + + #[cfg(not(feature = "nightly"))] + pub fn null() -> Atomic { + Atomic { + ptr: atomic::AtomicPtr::new(0 as *mut _), + _marker: PhantomData + } + } + + /// Create a new atomic pointer + pub fn new(data: T) -> Atomic { + Atomic { + ptr: atomic::AtomicPtr::new(Box::into_raw(Box::new(data))), + _marker: PhantomData + } + } + + /// Do an atomic load with the given memory ordering. + /// + /// In order to perform the load, we must pass in a borrow of a + /// `Guard`. This is a way of guaranteeing that the thread has pinned the + /// epoch for the entire lifetime `'a`. In return, you get an optional + /// `Shared` pointer back (`None` if the `Atomic` is currently null), with + /// lifetime tied to the guard. + /// + /// # Panics + /// + /// Panics if `ord` is `Release` or `AcqRel`. + pub fn load<'a>(&self, ord: Ordering, _: &'a Guard) -> Option> { + unsafe { Shared::from_raw(self.ptr.load(ord)) } + } + + /// Do an atomic store with the given memory ordering. + /// + /// Transfers ownership of the given `Owned` pointer, if any. Since no + /// lifetime information is acquired, no `Guard` value is needed. + /// + /// # Panics + /// + /// Panics if `ord` is `Acquire` or `AcqRel`. + pub fn store(&self, val: Option>, ord: Ordering) { + self.ptr.store(opt_owned_into_raw(val), ord) + } + + /// Do an atomic store with the given memory ordering, immediately yielding + /// a shared reference to the pointer that was stored. + /// + /// Transfers ownership of the given `Owned` pointer, yielding a `Shared` + /// reference to it. Since the reference is valid only for the curent epoch, + /// it's lifetime is tied to a `Guard` value. + /// + /// # Panics + /// + /// Panics if `ord` is `Acquire` or `AcqRel`. + pub fn store_and_ref<'a>(&self, val: Owned, ord: Ordering, _: &'a Guard) + -> Shared<'a, T> + { + unsafe { + let shared = Shared::from_owned(val); + self.store_shared(Some(shared), ord); + shared + } + } + + /// Do an atomic store of a `Shared` pointer with the given memory ordering. + /// + /// This operation does not require a guard, because it does not yield any + /// new information about the lifetime of a pointer. + /// + /// # Panics + /// + /// Panics if `ord` is `Acquire` or `AcqRel`. + pub fn store_shared(&self, val: Option>, ord: Ordering) { + self.ptr.store(opt_shared_into_raw(val), ord) + } + + /// Do a compare-and-set from a `Shared` to an `Owned` pointer with the + /// given memory ordering. + /// + /// As with `store`, this operation does not require a guard; it produces no new + /// lifetime information. The `Result` indicates whether the CAS succeeded; if + /// not, ownership of the `new` pointer is returned to the caller. + pub fn cas(&self, old: Option>, new: Option>, ord: Ordering) + -> Result<(), Option>> + { + if self.ptr.compare_and_swap(opt_shared_into_raw(old), + opt_owned_as_raw(&new), + ord) == opt_shared_into_raw(old) + { + mem::forget(new); + Ok(()) + } else { + Err(new) + } + } + + /// Do a compare-and-set from a `Shared` to an `Owned` pointer with the + /// given memory ordering, immediatley acquiring a new `Shared` reference to + /// the previously-owned pointer if successful. + /// + /// This operation is analogous to `store_and_ref`. + pub fn cas_and_ref<'a>(&self, old: Option>, new: Owned, + ord: Ordering, _: &'a Guard) + -> Result, Owned> + { + if self.ptr.compare_and_swap(opt_shared_into_raw(old), new.as_raw(), ord) + == opt_shared_into_raw(old) + { + Ok(unsafe { Shared::from_owned(new) }) + } else { + Err(new) + } + } + + /// Do a compare-and-set from a `Shared` to another `Shared` pointer with + /// the given memory ordering. + /// + /// The boolean return value is `true` when the CAS is successful. + pub fn cas_shared(&self, old: Option>, new: Option>, ord: Ordering) + -> bool + { + self.ptr.compare_and_swap(opt_shared_into_raw(old), + opt_shared_into_raw(new), + ord) == opt_shared_into_raw(old) + } + + /// Do an atomic swap with an `Owned` pointer with the given memory ordering. + pub fn swap<'a>(&self, new: Option>, ord: Ordering, _: &'a Guard) + -> Option> { + unsafe { Shared::from_raw(self.ptr.swap(opt_owned_into_raw(new), ord)) } + } + + /// Do an atomic swap with a `Shared` pointer with the given memory ordering. + pub fn swap_shared<'a>(&self, new: Option>, ord: Ordering, _: &'a Guard) + -> Option> { + unsafe { Shared::from_raw(self.ptr.swap(opt_shared_into_raw(new), ord)) } + } +} diff --git a/crossbeam-0.2.12/src/mem/epoch/garbage.rs b/crossbeam-0.2.12/src/mem/epoch/garbage.rs new file mode 100644 index 000000000..f71f66b6a --- /dev/null +++ b/crossbeam-0.2.12/src/mem/epoch/garbage.rs @@ -0,0 +1,144 @@ +// Data structures for storing garbage to be freed later (once the +// epochs have sufficiently advanced). +// +// In general, we try to manage the garbage thread locally whenever +// possible. Each thread keep track of three bags of garbage. But if a +// thread is exiting, these bags must be moved into the global garbage +// bags. + +use std::ptr; +use std::mem; +use std::sync::atomic::AtomicPtr; +use std::sync::atomic::Ordering::{Relaxed, Release, Acquire}; + +use mem::ZerosValid; + +/// One item of garbage. +/// +/// Stores enough information to do a deallocation. +#[derive(Debug)] +struct Item { + ptr: *mut u8, + free: unsafe fn(*mut u8), +} + +/// A single, thread-local bag of garbage. +#[derive(Debug)] +pub struct Bag(Vec); + +impl Bag { + fn new() -> Bag { + Bag(vec![]) + } + + fn insert(&mut self, elem: *mut T) { + let size = mem::size_of::(); + if size > 0 { + self.0.push(Item { + ptr: elem as *mut u8, + free: free::, + }) + } + unsafe fn free(t: *mut u8) { + drop(Vec::from_raw_parts(t as *mut T, 0, 1)); + } + } + + fn len(&self) -> usize { + self.0.len() + } + + /// Deallocate all garbage in the bag + pub unsafe fn collect(&mut self) { + let mut data = mem::replace(&mut self.0, Vec::new()); + for item in data.iter() { + (item.free)(item.ptr); + } + data.truncate(0); + self.0 = data; + } +} + +// needed because the bags store raw pointers. +unsafe impl Send for Bag {} +unsafe impl Sync for Bag {} + +/// A thread-local set of garbage bags. +#[derive(Debug)] +pub struct Local { + /// Garbage added at least one epoch behind the current local epoch + pub old: Bag, + /// Garbage added in the current local epoch or earlier + pub cur: Bag, + /// Garbage added in the current *global* epoch + pub new: Bag, +} + +impl Local { + pub fn new() -> Local { + Local { + old: Bag::new(), + cur: Bag::new(), + new: Bag::new(), + } + } + + pub fn insert(&mut self, elem: *mut T) { + self.new.insert(elem) + } + + /// Collect one epoch of garbage, rotating the local garbage bags. + pub unsafe fn collect(&mut self) { + let ret = self.old.collect(); + mem::swap(&mut self.old, &mut self.cur); + mem::swap(&mut self.cur, &mut self.new); + ret + } + + pub fn size(&self) -> usize { + self.old.len() + self.cur.len() + self.new.len() + } +} + +/// A concurrent garbage bag, currently based on Treiber's stack. +/// +/// The elements are themselves owned `Bag`s. +#[derive(Debug)] +pub struct ConcBag { + head: AtomicPtr, +} + +unsafe impl ZerosValid for ConcBag {} + +#[derive(Debug)] +struct Node { + data: Bag, + next: AtomicPtr, +} + +impl ConcBag { + pub fn insert(&self, t: Bag){ + let n = Box::into_raw(Box::new( + Node { data: t, next: AtomicPtr::new(ptr::null_mut()) })); + loop { + let head = self.head.load(Acquire); + unsafe { (*n).next.store(head, Relaxed) }; + if self.head.compare_and_swap(head, n, Release) == head { break } + } + } + + pub unsafe fn collect(&self) { + // check to avoid xchg instruction + // when no garbage exists + let mut head = self.head.load(Relaxed); + if head != ptr::null_mut() { + head = self.head.swap(ptr::null_mut(), Acquire); + + while head != ptr::null_mut() { + let mut n = Box::from_raw(head); + n.data.collect(); + head = n.next.load(Relaxed); + } + } + } +} diff --git a/crossbeam-0.2.12/src/mem/epoch/global.rs b/crossbeam-0.2.12/src/mem/epoch/global.rs new file mode 100644 index 000000000..f253b4ea4 --- /dev/null +++ b/crossbeam-0.2.12/src/mem/epoch/global.rs @@ -0,0 +1,95 @@ +// Definition of global epoch state. The `get` function is the way to +// access this data externally (until const fn is stabilized...). + +use std::sync::atomic::AtomicUsize; + +use mem::CachePadded; +use mem::epoch::garbage; +use mem::epoch::participants::Participants; + +/// Global epoch state +#[derive(Debug)] +pub struct EpochState { + /// Current global epoch + pub epoch: CachePadded, + + // FIXME: move this into the `garbage` module, rationalize API + /// Global garbage bags + pub garbage: [CachePadded; 3], + + /// Participant list + pub participants: Participants, +} + +unsafe impl Send for EpochState {} +unsafe impl Sync for EpochState {} + +pub use self::imp::get; + +#[cfg(not(feature = "nightly"))] +mod imp { + use std::mem; + use std::sync::atomic::{self, AtomicUsize}; + use std::sync::atomic::Ordering::Relaxed; + + use super::EpochState; + use mem::CachePadded; + use mem::epoch::participants::Participants; + + impl EpochState { + fn new() -> EpochState { + EpochState { + epoch: CachePadded::zeroed(), + garbage: [CachePadded::zeroed(), + CachePadded::zeroed(), + CachePadded::zeroed()], + participants: Participants::new(), + } + } + } + + static EPOCH: AtomicUsize = atomic::ATOMIC_USIZE_INIT; + + pub fn get() -> &'static EpochState { + let mut addr = EPOCH.load(Relaxed); + + if addr == 0 { + let boxed = Box::new(EpochState::new()); + let raw = Box::into_raw(boxed); + + addr = EPOCH.compare_and_swap(0, raw as usize, Relaxed); + if addr != 0 { + let boxed = unsafe { Box::from_raw(raw) }; + mem::drop(boxed); + } else { + addr = raw as usize; + } + } + + unsafe { + &*(addr as *mut EpochState) + } + } +} + +#[cfg(feature = "nightly")] +mod imp { + use super::EpochState; + use mem::CachePadded; + use mem::epoch::participants::Participants; + + impl EpochState { + const fn new() -> EpochState { + EpochState { + epoch: CachePadded::zeroed(), + garbage: [CachePadded::zeroed(), + CachePadded::zeroed(), + CachePadded::zeroed()], + participants: Participants::new(), + } + } + } + + static EPOCH: EpochState = EpochState::new(); + pub fn get() -> &'static EpochState { &EPOCH } +} diff --git a/crossbeam-0.2.12/src/mem/epoch/guard.rs b/crossbeam-0.2.12/src/mem/epoch/guard.rs new file mode 100644 index 000000000..91f9685a2 --- /dev/null +++ b/crossbeam-0.2.12/src/mem/epoch/guard.rs @@ -0,0 +1,56 @@ +use std::marker; + +use super::{local, Shared}; + +/// An RAII-style guard for pinning the current epoch. +/// +/// A guard must be acquired before most operations on an `Atomic` pointer. On +/// destruction, it unpins the epoch. +#[must_use] +#[derive(Debug)] +pub struct Guard { + _marker: marker::PhantomData<*mut ()>, // !Send and !Sync +} + +/// Pin the current epoch. +/// +/// Threads generally pin before interacting with a lock-free data +/// structure. Pinning requires a full memory barrier, so is somewhat +/// expensive. It is rentrant -- you can safely acquire nested guards, and only +/// the first guard requires a barrier. Thus, in cases where you expect to +/// perform several lock-free operations in quick succession, you may consider +/// pinning around the entire set of operations. +pub fn pin() -> Guard { + local::with_participant(|p| { + p.enter(); + + let g = Guard { + _marker: marker::PhantomData, + }; + + if p.should_gc() { + p.try_collect(&g); + } + + g + }) +} + +impl Guard { + /// Assert that the value is no longer reachable from a lock-free data + /// structure and should be collected when sufficient epochs have passed. + pub unsafe fn unlinked(&self, val: Shared) { + local::with_participant(|p| p.reclaim(val.as_raw())) + } + + /// Move the thread-local garbage into the global set of garbage. + pub fn migrate_garbage(&self) { + local::with_participant(|p| p.migrate_garbage()) + } +} + +impl Drop for Guard { + fn drop(&mut self) { + local::with_participant(|p| p.exit()); + } +} diff --git a/crossbeam-0.2.12/src/mem/epoch/local.rs b/crossbeam-0.2.12/src/mem/epoch/local.rs new file mode 100644 index 000000000..8c8bd1cd5 --- /dev/null +++ b/crossbeam-0.2.12/src/mem/epoch/local.rs @@ -0,0 +1,38 @@ +// Manage the thread-local state, providing access to a `Participant` record. + +use std::sync::atomic::Ordering::Relaxed; + +use mem::epoch::participant::Participant; +use mem::epoch::global; + +#[derive(Debug)] +struct LocalEpoch { + participant: *const Participant, +} + +impl LocalEpoch { + fn new() -> LocalEpoch { + LocalEpoch { participant: global::get().participants.enroll() } + } + + fn get(&self) -> &Participant { + unsafe { &*self.participant } + } +} + +// FIXME: avoid leaking when all threads have exited +impl Drop for LocalEpoch { + fn drop(&mut self) { + let p = self.get(); + p.enter(); + p.migrate_garbage(); + p.exit(); + p.active.store(false, Relaxed); + } +} + +thread_local!(static LOCAL_EPOCH: LocalEpoch = LocalEpoch::new() ); + +pub fn with_participant(f: F) -> T where F: FnOnce(&Participant) -> T { + LOCAL_EPOCH.with(|e| f(e.get())) +} diff --git a/crossbeam-0.2.12/src/mem/epoch/mod.rs b/crossbeam-0.2.12/src/mem/epoch/mod.rs new file mode 100644 index 000000000..3a83cf610 --- /dev/null +++ b/crossbeam-0.2.12/src/mem/epoch/mod.rs @@ -0,0 +1,265 @@ +//! Epoch-based memory management +//! +//! This module provides fast, easy to use memory management for lock free data +//! structures. It's inspired by [Keir Fraser's *epoch-based +//! reclamation*](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf). +//! +//! The basic problem this is solving is the fact that when one thread has +//! removed a node from a data structure, other threads may still have pointers +//! to that node (in the form of snapshots that will be validated through things +//! like compare-and-swap), so the memory cannot be immediately freed. Put differently: +//! +//! 1. There are two sources of reachability at play -- the data structure, and +//! the snapshots in threads accessing it. Before we delete a node, we need to know +//! that it cannot be reached in either of these ways. +//! +//! 2. Once a node has been unliked from the data structure, no *new* snapshots +//! reaching it will be created. +//! +//! Using the epoch scheme is fairly straightforward, and does not require +//! understanding any of the implementation details: +//! +//! - When operating on a shared data structure, a thread must "pin the current +//! epoch", which is done by calling `pin()`. This function returns a `Guard` +//! which unpins the epoch when destroyed. +//! +//! - When the thread subsequently reads from a lock-free data structure, the +//! pointers it extracts act like references with lifetime tied to the +//! `Guard`. This allows threads to safely read from snapshotted data, being +//! guaranteed that the data will remain allocated until they exit the epoch. +//! +//! To put the `Guard` to use, Crossbeam provides a set of three pointer types meant to work together: +//! +//! - `Owned`, akin to `Box`, which points to uniquely-owned data that has +//! not yet been published in a concurrent data structure. +//! +//! - `Shared<'a, T>`, akin to `&'a T`, which points to shared data that may or may +//! not be reachable from a data structure, but it guaranteed not to be freed +//! during lifetime `'a`. +//! +//! - `Atomic`, akin to `std::sync::atomic::AtomicPtr`, which provides atomic +//! updates to a pointer using the `Owned` and `Shared` types, and connects them +//! to a `Guard`. +//! +//! Each of these types provides further documentation on usage. +//! +//! # Example +//! +//! ``` +//! use std::sync::atomic::Ordering::{Acquire, Release, Relaxed}; +//! use std::ptr; +//! +//! use crossbeam::mem::epoch::{self, Atomic, Owned}; +//! +//! struct TreiberStack { +//! head: Atomic>, +//! } +//! +//! struct Node { +//! data: T, +//! next: Atomic>, +//! } +//! +//! impl TreiberStack { +//! fn new() -> TreiberStack { +//! TreiberStack { +//! head: Atomic::null() +//! } +//! } +//! +//! fn push(&self, t: T) { +//! // allocate the node via Owned +//! let mut n = Owned::new(Node { +//! data: t, +//! next: Atomic::null(), +//! }); +//! +//! // become active +//! let guard = epoch::pin(); +//! +//! loop { +//! // snapshot current head +//! let head = self.head.load(Relaxed, &guard); +//! +//! // update `next` pointer with snapshot +//! n.next.store_shared(head, Relaxed); +//! +//! // if snapshot is still good, link in the new node +//! match self.head.cas_and_ref(head, n, Release, &guard) { +//! Ok(_) => return, +//! Err(owned) => n = owned, +//! } +//! } +//! } +//! +//! fn pop(&self) -> Option { +//! // become active +//! let guard = epoch::pin(); +//! +//! loop { +//! // take a snapshot +//! match self.head.load(Acquire, &guard) { +//! // the stack is non-empty +//! Some(head) => { +//! // read through the snapshot, *safely*! +//! let next = head.next.load(Relaxed, &guard); +//! +//! // if snapshot is still good, update from `head` to `next` +//! if self.head.cas_shared(Some(head), next, Release) { +//! unsafe { +//! // mark the node as unlinked +//! guard.unlinked(head); +//! +//! // extract out the data from the now-unlinked node +//! return Some(ptr::read(&(*head).data)) +//! } +//! } +//! } +//! +//! // we observed the stack empty +//! None => return None +//! } +//! } +//! } +//! } +//! ``` + +// FIXME: document implementation details + +mod atomic; +mod garbage; +mod global; +mod guard; +mod local; +mod participant; +mod participants; + +pub use self::atomic::Atomic; +pub use self::guard::{pin, Guard}; + +use std::ops::{Deref, DerefMut}; +use std::ptr; +use std::mem; + +/// Like `Box`: an owned, heap-allocated data value of type `T`. +#[derive(Debug)] +pub struct Owned { + data: Box, +} + +impl Owned { + /// Move `t` to a new heap allocation. + pub fn new(t: T) -> Owned { + Owned { data: Box::new(t) } + } + + fn as_raw(&self) -> *mut T { + self.deref() as *const _ as *mut _ + } + + /// Move data out of the owned box, deallocating the box. + pub fn into_inner(self) -> T { + *self.data + } +} + +impl Deref for Owned { + type Target = T; + fn deref(&self) -> &T { + &self.data + } +} + +impl DerefMut for Owned { + fn deref_mut(&mut self) -> &mut T { + &mut self.data + } +} + +#[derive(PartialEq, Eq)] +/// Like `&'a T`: a shared reference valid for lifetime `'a`. +#[derive(Debug)] +pub struct Shared<'a, T: 'a> { + data: &'a T, +} + +impl<'a, T> Copy for Shared<'a, T> {} +impl<'a, T> Clone for Shared<'a, T> { + fn clone(&self) -> Shared<'a, T> { + Shared { data: self.data } + } +} + +impl<'a, T> Deref for Shared<'a, T> { + type Target = &'a T; + fn deref(&self) -> &&'a T { + &self.data + } +} + +impl<'a, T> Shared<'a, T> { + unsafe fn from_raw(raw: *mut T) -> Option> { + if raw == ptr::null_mut() { None } + else { + Some(Shared { + data: mem::transmute::<*mut T, &T>(raw) + }) + } + } + + unsafe fn from_ref(r: &T) -> Shared<'a, T> { + Shared { data: mem::transmute(r) } + } + + unsafe fn from_owned(owned: Owned) -> Shared<'a, T> { + let ret = Shared::from_ref(owned.deref()); + mem::forget(owned); + ret + } + + pub fn as_raw(&self) -> *mut T { + self.data as *const _ as *mut _ + } +} + + +#[cfg(test)] +mod test { + use std::sync::atomic::Ordering; + use super::*; + use mem::epoch; + + #[test] + fn test_no_drop() { + static mut DROPS: i32 = 0; + struct Test; + impl Drop for Test { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + } + } + let g = pin(); + + let x = Atomic::null(); + x.store(Some(Owned::new(Test)), Ordering::Relaxed); + x.store_and_ref(Owned::new(Test), Ordering::Relaxed, &g); + let y = x.load(Ordering::Relaxed, &g); + let z = x.cas_and_ref(y, Owned::new(Test), Ordering::Relaxed, &g).ok(); + let _ = x.cas(z, Some(Owned::new(Test)), Ordering::Relaxed); + x.swap(Some(Owned::new(Test)), Ordering::Relaxed, &g); + + unsafe { + assert_eq!(DROPS, 0); + } + } + + #[test] + fn test_new() { + let guard = epoch::pin(); + let my_atomic = Atomic::new(42); + + assert_eq!(**my_atomic.load(Ordering::Relaxed, &guard).unwrap(), 42); + } +} diff --git a/crossbeam-0.2.12/src/mem/epoch/participant.rs b/crossbeam-0.2.12/src/mem/epoch/participant.rs new file mode 100644 index 000000000..213305e4f --- /dev/null +++ b/crossbeam-0.2.12/src/mem/epoch/participant.rs @@ -0,0 +1,133 @@ +// Manages a single participant in the epoch scheme. This is where all +// of the actual epoch management logic happens! + +use std::mem; +use std::cell::UnsafeCell; +use std::fmt; +use std::sync::atomic::{self, AtomicUsize, AtomicBool}; +use std::sync::atomic::Ordering::{Relaxed, Acquire, Release, SeqCst}; + +use mem::epoch::{Atomic, Guard, garbage, global}; +use mem::epoch::participants::ParticipantNode; + +/// Thread-local data for epoch participation. +pub struct Participant { + /// The local epoch. + epoch: AtomicUsize, + + /// Number of pending uses of `epoch::pin()`; keeping a count allows for + /// reentrant use of epoch management. + in_critical: AtomicUsize, + + /// Thread-local garbage tracking + garbage: UnsafeCell, + + /// Is the thread still active? Becomes `false` when the thread exits. This + /// is ultimately used to free `Participant` records. + pub active: AtomicBool, + + /// The participant list is coded intrusively; here's the `next` pointer. + pub next: Atomic, +} + +impl fmt::Debug for Participant { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Participant {{ ... }}") + } +} + +unsafe impl Sync for Participant {} + +const GC_THRESH: usize = 32; + +impl Participant { + pub fn new() -> Participant { + Participant { + epoch: AtomicUsize::new(0), + in_critical: AtomicUsize::new(0), + active: AtomicBool::new(true), + garbage: UnsafeCell::new(garbage::Local::new()), + next: Atomic::null(), + } + } + + /// Enter a critical section. + /// + /// This method is reentrant, allowing for nested critical sections. + /// + /// Returns `true` is this is the first entry on the stack (as opposed to a + /// re-entrant call). + pub fn enter(&self) -> bool { + let new_count = self.in_critical.load(Relaxed) + 1; + self.in_critical.store(new_count, Relaxed); + if new_count > 1 { return false } + + atomic::fence(SeqCst); + + let global_epoch = global::get().epoch.load(Relaxed); + if global_epoch != self.epoch.load(Relaxed) { + self.epoch.store(global_epoch, Relaxed); + unsafe { (*self.garbage.get()).collect(); } + } + + true + } + + /// Exit the current (nested) critical section. + pub fn exit(&self) { + let new_count = self.in_critical.load(Relaxed) - 1; + self.in_critical.store( + new_count, + if new_count > 0 { Relaxed } else { Release }); + } + + /// Begin the reclamation process for a piece of data. + pub unsafe fn reclaim(&self, data: *mut T) { + (*self.garbage.get()).insert(data); + } + + /// Attempt to collect garbage by moving the global epoch forward. + /// + /// Returns `true` on success. + pub fn try_collect(&self, guard: &Guard) -> bool { + let cur_epoch = global::get().epoch.load(SeqCst); + + for p in global::get().participants.iter(guard) { + if p.in_critical.load(Relaxed) > 0 && p.epoch.load(Relaxed) != cur_epoch { + return false + } + } + + let new_epoch = cur_epoch.wrapping_add(1); + atomic::fence(Acquire); + if global::get().epoch.compare_and_swap(cur_epoch, new_epoch, SeqCst) != cur_epoch { + return false + } + + unsafe { + (*self.garbage.get()).collect(); + global::get().garbage[new_epoch.wrapping_add(1) % 3].collect(); + } + self.epoch.store(new_epoch, Release); + + true + } + + /// Move the current thread-local garbage into the global garbage bags. + pub fn migrate_garbage(&self) { + let cur_epoch = self.epoch.load(Relaxed); + let local = unsafe { mem::replace(&mut *self.garbage.get(), garbage::Local::new()) }; + global::get().garbage[cur_epoch.wrapping_sub(1) % 3].insert(local.old); + global::get().garbage[cur_epoch % 3].insert(local.cur); + global::get().garbage[global::get().epoch.load(Relaxed) % 3].insert(local.new); + } + + /// How much garbage is this participant currently storing? + pub fn garbage_size(&self) -> usize { + unsafe { (*self.garbage.get()).size() } + } + /// Is this participant past its local GC threshhold? + pub fn should_gc(&self) -> bool { + self.garbage_size() >= GC_THRESH + } +} diff --git a/crossbeam-0.2.12/src/mem/epoch/participants.rs b/crossbeam-0.2.12/src/mem/epoch/participants.rs new file mode 100644 index 000000000..784800e93 --- /dev/null +++ b/crossbeam-0.2.12/src/mem/epoch/participants.rs @@ -0,0 +1,120 @@ +// Manages the global participant list, which is an intrustive list in +// which items are lazily removed on traversal (after being +// "logically" deleted by becoming inactive.) + +use std::mem; +use std::ops::{Deref, DerefMut}; +use std::sync::atomic::Ordering::{Relaxed, Acquire, Release}; + +use mem::epoch::{Atomic, Owned, Guard}; +use mem::epoch::participant::Participant; +use mem::CachePadded; + +/// Global, threadsafe list of threads participating in epoch management. +#[derive(Debug)] +pub struct Participants { + head: Atomic +} + +#[derive(Debug)] +pub struct ParticipantNode(CachePadded); + +impl ParticipantNode { + pub fn new() -> ParticipantNode { + ParticipantNode(CachePadded::new(Participant::new())) + } +} + +impl Deref for ParticipantNode { + type Target = Participant; + fn deref(&self) -> &Participant { + &self.0 + } +} + +impl DerefMut for ParticipantNode { + fn deref_mut(&mut self) -> &mut Participant { + &mut self.0 + } +} + +impl Participants { + #[cfg(not(feature = "nightly"))] + pub fn new() -> Participants { + Participants { head: Atomic::null() } + } + + #[cfg(feature = "nightly")] + pub const fn new() -> Participants { + Participants { head: Atomic::null() } + } + + /// Enroll a new thread in epoch management by adding a new `Particpant` + /// record to the global list. + pub fn enroll(&self) -> *const Participant { + let mut participant = Owned::new(ParticipantNode::new()); + + // we ultimately use epoch tracking to free Participant nodes, but we + // can't actually enter an epoch here, so fake it; we know the node + // can't be removed until marked inactive anyway. + let fake_guard = (); + let g: &'static Guard = unsafe { mem::transmute(&fake_guard) }; + loop { + let head = self.head.load(Relaxed, g); + participant.next.store_shared(head, Relaxed); + match self.head.cas_and_ref(head, participant, Release, g) { + Ok(shared) => { + let shared: &Participant = &shared; + return shared; + } + Err(owned) => { + participant = owned; + } + } + } + } + + pub fn iter<'a>(&'a self, g: &'a Guard) -> Iter<'a> { + Iter { + guard: g, + next: &self.head, + needs_acq: true, + } + } +} + +#[derive(Debug)] +pub struct Iter<'a> { + // pin to an epoch so that we can free inactive nodes + guard: &'a Guard, + next: &'a Atomic, + + // an Acquire read is needed only for the first read, due to release + // sequences + needs_acq: bool, +} + +impl<'a> Iterator for Iter<'a> { + type Item = &'a Participant; + fn next(&mut self) -> Option<&'a Participant> { + let mut cur = if self.needs_acq { + self.needs_acq = false; + self.next.load(Acquire, self.guard) + } else { + self.next.load(Relaxed, self.guard) + }; + + while let Some(n) = cur { + // attempt to clean up inactive nodes + if !n.active.load(Relaxed) { + cur = n.next.load(Relaxed, self.guard); + // TODO: actually reclaim inactive participants! + } else { + self.next = &n.next; + return Some(&n) + } + } + + None + } +} diff --git a/crossbeam-0.2.12/src/mem/mod.rs b/crossbeam-0.2.12/src/mem/mod.rs new file mode 100644 index 000000000..841951007 --- /dev/null +++ b/crossbeam-0.2.12/src/mem/mod.rs @@ -0,0 +1,9 @@ +//! Memory management for concurrent data structures +//! +//! At the moment, the only memory management scheme is epoch-based reclamation, +//! found in the `epoch` submodule. + +pub use self::cache_padded::{CachePadded, ZerosValid}; + +pub mod epoch; +mod cache_padded; diff --git a/crossbeam-0.2.12/src/scoped.rs b/crossbeam-0.2.12/src/scoped.rs new file mode 100644 index 000000000..455fb683d --- /dev/null +++ b/crossbeam-0.2.12/src/scoped.rs @@ -0,0 +1,275 @@ +use std::cell::RefCell; +use std::fmt; +use std::mem; +use std::rc::Rc; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::thread; + +use {spawn_unsafe, FnBox}; +use sync::AtomicOption; + +pub struct Scope<'a> { + dtors: RefCell>> +} + +struct DtorChain<'a> { + dtor: Box, + next: Option>> +} + +enum JoinState { + Running(thread::JoinHandle<()>), + Joined, +} + +impl JoinState { + fn join(&mut self) { + let mut state = JoinState::Joined; + mem::swap(self, &mut state); + if let JoinState::Running(handle) = state { + let res = handle.join(); + + if !thread::panicking() { res.unwrap(); } + } + } +} + +/// A handle to a scoped thread +pub struct ScopedJoinHandle { + inner: Rc>, + packet: Arc>, + thread: thread::Thread, +} + +/// Create a new `scope`, for deferred destructors. +/// +/// Scopes, in particular, support [*scoped thread spawning*](struct.Scope.html#method.spawn). +/// +/// # Examples +/// +/// Creating and using a scope: +/// +/// ``` +/// crossbeam::scope(|scope| { +/// scope.defer(|| println!("Exiting scope")); +/// scope.spawn(|| println!("Running child thread in scope")) +/// }); +/// // Prints messages in the reverse order written +/// ``` +pub fn scope<'a, F, R>(f: F) -> R where F: FnOnce(&Scope<'a>) -> R { + let mut scope = Scope { dtors: RefCell::new(None) }; + let ret = f(&scope); + scope.drop_all(); + ret +} + +impl<'a> fmt::Debug for Scope<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Scope {{ ... }}") + } +} + +impl fmt::Debug for ScopedJoinHandle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ScopedJoinHandle {{ ... }}") + } +} + +impl<'a> Scope<'a> { + // This method is carefully written in a transactional style, so + // that it can be called directly and, if any dtor panics, can be + // resumed in the unwinding this causes. By initially running the + // method outside of any destructor, we avoid any leakage problems + // due to @rust-lang/rust#14875. + fn drop_all(&mut self) { + loop { + // use a separate scope to ensure that the RefCell borrow + // is relinquishe before running `dtor` + let dtor = { + let mut dtors = self.dtors.borrow_mut(); + if let Some(mut node) = dtors.take() { + *dtors = node.next.take().map(|b| *b); + node.dtor + } else { + return + } + }; + dtor.call_box() + } + } + + /// Schedule code to be executed when exiting the scope. + /// + /// This is akin to having a destructor on the stack, except that it is + /// *guaranteed* to be run. + pub fn defer(&self, f: F) where F: FnOnce() + 'a { + let mut dtors = self.dtors.borrow_mut(); + *dtors = Some(DtorChain { + dtor: Box::new(f), + next: dtors.take().map(Box::new) + }); + } + + /// Create a scoped thread. + /// + /// `spawn` is similar to the [`spawn`][spawn] function in Rust's standard library. The + /// difference is that this thread is scoped, meaning that it's guaranteed to terminate + /// before the current stack frame goes away, allowing you to reference the parent stack frame + /// directly. This is ensured by having the parent thread join on the child thread before the + /// scope exits. + /// + /// [spawn]: http://doc.rust-lang.org/std/thread/fn.spawn.html + /// + /// # Examples + /// + /// A basic scoped thread: + /// + /// ``` + /// crossbeam::scope(|scope| { + /// scope.spawn(|| { + /// println!("Hello from a scoped thread!"); + /// }); + /// }); + /// ``` + /// + /// When writing concurrent Rust programs, you'll sometimes see a pattern like this, using + /// [`std::thread::spawn`][spawn]: + /// + /// ```ignore + /// let array = [1, 2, 3]; + /// let mut guards = vec![]; + /// + /// for i in &array { + /// let guard = std::thread::spawn(move || { + /// println!("element: {}", i); + /// }); + /// + /// guards.push(guard); + /// } + /// + /// for guard in guards { + /// guard.join().unwrap(); + /// } + /// ``` + /// + /// The basic pattern is: + /// + /// 1. Iterate over some collection. + /// 2. Spin up a thread to operate on each part of the collection. + /// 3. Join all the threads. + /// + /// However, this code actually gives an error: + /// + /// ```text + /// error: `array` does not live long enough + /// for i in &array { + /// ^~~~~ + /// in expansion of for loop expansion + /// note: expansion site + /// note: reference must be valid for the static lifetime... + /// note: ...but borrowed value is only valid for the block suffix following statement 0 at ... + /// let array = [1, 2, 3]; + /// let mut guards = vec![]; + /// + /// for i in &array { + /// let guard = std::thread::spawn(move || { + /// println!("element: {}", i); + /// ... + /// error: aborting due to previous error + /// ``` + /// + /// Because [`std::thread::spawn`][spawn] doesn't know about this scope, it requires a + /// `'static` lifetime. One way of giving it a proper lifetime is to use an [`Arc`][arc]: + /// + /// [arc]: http://doc.rust-lang.org/stable/std/sync/struct.Arc.html + /// + /// ``` + /// use std::sync::Arc; + /// + /// let array = Arc::new([1, 2, 3]); + /// let mut guards = vec![]; + /// + /// for i in (0..array.len()) { + /// let a = array.clone(); + /// + /// let guard = std::thread::spawn(move || { + /// println!("element: {}", a[i]); + /// }); + /// + /// guards.push(guard); + /// } + /// + /// for guard in guards { + /// guard.join().unwrap(); + /// } + /// ``` + /// + /// But this introduces unnecessary allocation, as `Arc` puts its data on the heap, and we + /// also end up dealing with reference counts. We know that we're joining the threads before + /// our function returns, so just taking a reference _should_ be safe. Rust can't know that, + /// though. + /// + /// Enter scoped threads. Here's our original example, using `spawn` from crossbeam rather + /// than from `std::thread`: + /// + /// ``` + /// let array = [1, 2, 3]; + /// + /// crossbeam::scope(|scope| { + /// for i in &array { + /// scope.spawn(move || { + /// println!("element: {}", i); + /// }); + /// } + /// }); + /// ``` + /// + /// Much more straightforward. + pub fn spawn(&self, f: F) -> ScopedJoinHandle where + F: FnOnce() -> T + Send + 'a, T: Send + 'a + { + let their_packet = Arc::new(AtomicOption::new()); + let my_packet = their_packet.clone(); + + let join_handle = unsafe { + spawn_unsafe(move || { + their_packet.swap(f(), Ordering::Relaxed); + }) + }; + + let thread = join_handle.thread().clone(); + let deferred_handle = Rc::new(RefCell::new(JoinState::Running(join_handle))); + let my_handle = deferred_handle.clone(); + + self.defer(move || { + let mut state = deferred_handle.borrow_mut(); + state.join(); + }); + + ScopedJoinHandle { + inner: my_handle, + packet: my_packet, + thread: thread, + } + } +} + +impl ScopedJoinHandle { + /// Join the scoped thread, returning the result it produced. + pub fn join(self) -> T { + self.inner.borrow_mut().join(); + self.packet.take(Ordering::Relaxed).unwrap() + } + + /// Get the underlying thread handle. + pub fn thread(&self) -> &thread::Thread { + &self.thread + } +} + +impl<'a> Drop for Scope<'a> { + fn drop(&mut self) { + self.drop_all() + } +} diff --git a/crossbeam-0.2.12/src/sync/arc_cell.rs b/crossbeam-0.2.12/src/sync/arc_cell.rs new file mode 100644 index 000000000..e26d45a94 --- /dev/null +++ b/crossbeam-0.2.12/src/sync/arc_cell.rs @@ -0,0 +1,90 @@ +use std::marker::PhantomData; +use std::mem; +use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering}; + +/// A type providing atomic storage and retrieval of an `Arc`. +#[derive(Debug)] +pub struct ArcCell(AtomicUsize, PhantomData>); + +impl Drop for ArcCell { + fn drop(&mut self) { + self.take(); + } +} + +impl ArcCell { + /// Creates a new `ArcCell`. + pub fn new(t: Arc) -> ArcCell { + ArcCell(AtomicUsize::new(unsafe { mem::transmute(t) }), PhantomData) + } + + fn take(&self) -> Arc { + loop { + match self.0.swap(0, Ordering::Acquire) { + 0 => {} + n => return unsafe { mem::transmute(n) } + } + } + } + + fn put(&self, t: Arc) { + debug_assert_eq!(self.0.load(Ordering::SeqCst), 0); + self.0.store(unsafe { mem::transmute(t) }, Ordering::Release); + } + + /// Stores a new value in the `ArcCell`, returning the previous + /// value. + pub fn set(&self, t: Arc) -> Arc { + let old = self.take(); + self.put(t); + old + } + + /// Returns a copy of the value stored by the `ArcCell`. + pub fn get(&self) -> Arc { + let t = self.take(); + // NB: correctness here depends on Arc's clone impl not panicking + let out = t.clone(); + self.put(t); + out + } +} + +#[cfg(test)] +mod test { + use std::sync::Arc; + use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering}; + + use super::*; + + #[test] + fn basic() { + let r = ArcCell::new(Arc::new(0)); + assert_eq!(*r.get(), 0); + assert_eq!(*r.set(Arc::new(1)), 0); + assert_eq!(*r.get(), 1); + } + + #[test] + fn drop_runs() { + static DROPS: AtomicUsize = ATOMIC_USIZE_INIT; + + struct Foo; + + impl Drop for Foo { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let r = ArcCell::new(Arc::new(Foo)); + let _f = r.get(); + r.get(); + r.set(Arc::new(Foo)); + drop(_f); + assert_eq!(DROPS.load(Ordering::SeqCst), 1); + drop(r); + assert_eq!(DROPS.load(Ordering::SeqCst), 2); + } +} diff --git a/crossbeam-0.2.12/src/sync/atomic_option.rs b/crossbeam-0.2.12/src/sync/atomic_option.rs new file mode 100644 index 000000000..b67460670 --- /dev/null +++ b/crossbeam-0.2.12/src/sync/atomic_option.rs @@ -0,0 +1,38 @@ +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::ptr; + +unsafe impl Send for AtomicOption {} +unsafe impl Sync for AtomicOption {} + +#[derive(Debug)] +pub struct AtomicOption { + inner: AtomicPtr, +} + +impl AtomicOption { + pub fn new() -> AtomicOption { + AtomicOption { inner: AtomicPtr::new(ptr::null_mut()) } + } + + fn swap_inner(&self, ptr: *mut T, order: Ordering) -> Option> { + let old = self.inner.swap(ptr, order); + if old.is_null() { + None + } else { + Some(unsafe { Box::from_raw(old) }) + } + } + + // allows re-use of allocation + pub fn swap_box(&self, t: Box, order: Ordering) -> Option> { + self.swap_inner(Box::into_raw(t), order) + } + + pub fn swap(&self, t: T, order: Ordering) -> Option { + self.swap_box(Box::new(t), order).map(|old| *old) + } + + pub fn take(&self, order: Ordering) -> Option { + self.swap_inner(ptr::null_mut(), order).map(|old| *old) + } +} diff --git a/crossbeam-0.2.12/src/sync/chase_lev.rs b/crossbeam-0.2.12/src/sync/chase_lev.rs new file mode 100644 index 000000000..f72a8ea92 --- /dev/null +++ b/crossbeam-0.2.12/src/sync/chase_lev.rs @@ -0,0 +1,602 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A lock-free concurrent work-stealing deque +//! +//! This module contains a hybrid implementation of the Chase-Lev work stealing deque +//! described in ["Dynamic Circular Work-Stealing Deque"][chase_lev] and the improved version +//! described in ["Correct and Efficient Work-Stealing for Weak Memory Models"][weak_chase_lev]. +//! The implementation is heavily based on the pseudocode found in the papers. +//! +//! # Example +//! +//! ``` +//! use crossbeam::sync::chase_lev; +//! let (mut worker, stealer) = chase_lev::deque(); +//! +//! // Only the worker may push/try_pop +//! worker.push(1); +//! worker.try_pop(); +//! +//! // Stealers take data from the other end of the deque +//! worker.push(1); +//! stealer.steal(); +//! +//! // Stealers can be cloned to have many stealers stealing in parallel +//! worker.push(1); +//! let stealer2 = stealer.clone(); +//! stealer2.steal(); +//! ``` +//! +//! [chase_lev]: http://neteril.org/~jeremie/Dynamic_Circular_Work_Queue.pdf +//! [weak_chase_lev]: http://www.di.ens.fr/~zappa/readings/ppopp13.pdf + +use std::cell::UnsafeCell; +use std::fmt; +use std::mem; +use std::ptr; +use std::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; +use std::sync::atomic::{AtomicIsize, fence}; +use std::sync::Arc; + +use mem::epoch::{self, Atomic, Shared, Owned}; + +// Once the queue is less than 1/K full, then it will be downsized. Note that +// the deque requires that this number be less than 2. +const K: isize = 4; + +// Minimum number of bits that a buffer size should be. No buffer will resize to +// under this value, and all deques will initially contain a buffer of this +// size. +// +// The size in question is 1 << MIN_BITS +const MIN_BITS: u32 = 7; + +#[derive(Debug)] +struct Deque { + bottom: AtomicIsize, + top: AtomicIsize, + array: Atomic>, +} + +// FIXME: can these constraints be relaxed? +unsafe impl Send for Deque {} +unsafe impl Sync for Deque {} + +/// Worker half of the work-stealing deque. This worker has exclusive access to +/// one side of the deque, and uses `push` and `try_pop` method to manipulate it. +/// +/// There may only be one worker per deque, and operations on the worker +/// require mutable access to the worker itself. +#[derive(Debug)] +pub struct Worker { + deque: Arc>, +} + +/// The stealing half of the work-stealing deque. Stealers have access to the +/// opposite end of the deque from the worker, and they only have access to the +/// `steal` method. +/// +/// Stealers can be cloned to have more than one handle active at a time. +#[derive(Debug)] +pub struct Stealer { + deque: Arc>, +} + +/// When stealing some data, this is an enumeration of the possible outcomes. +#[derive(PartialEq, Eq, Debug)] +pub enum Steal { + /// The deque was empty at the time of stealing + Empty, + /// The stealer lost the race for stealing data, and a retry may return more + /// data. + Abort, + /// The stealer has successfully stolen some data. + Data(T), +} + +// An internal buffer used by the chase-lev deque. This structure is actually +// implemented as a circular buffer, and is used as the intermediate storage of +// the data in the deque. +// +// This Vec always has a length of 0, the backing buffer is just used by the +// code below. +struct Buffer { + storage: UnsafeCell>, + log_size: u32, +} + +impl fmt::Debug for Buffer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Buffer {{ ... }}") + } +} + +impl Worker { + /// Pushes data onto the front of this work queue. + pub fn push(&mut self, t: T) { + unsafe { self.deque.push(t) } + } + + /// Pops data off the front of the work queue, returning `None` on an empty + /// queue. + pub fn try_pop(&mut self) -> Option { + unsafe { self.deque.try_pop() } + } +} + +impl Stealer { + /// Steals work off the end of the queue (opposite of the worker's end) + pub fn steal(&self) -> Steal { + self.deque.steal() + } +} + +impl Clone for Stealer { + fn clone(&self) -> Stealer { + Stealer { deque: self.deque.clone() } + } +} + +/// Creates a new empty deque +pub fn deque() -> (Worker, Stealer) { + let a = Arc::new(Deque::new()); + let b = a.clone(); + (Worker { deque: a }, Stealer { deque: b }) +} + +// Almost all of this code can be found directly in the paper so I'm not +// personally going to heavily comment what's going on here. + +impl Deque { + fn new() -> Deque { + let array = Atomic::null(); + array.store(Some(Owned::new(Buffer::new(MIN_BITS))), SeqCst); + Deque { + bottom: AtomicIsize::new(0), + top: AtomicIsize::new(0), + array: array, + } + } + + unsafe fn push(&self, data: T) { + let guard = epoch::pin(); + + let mut b = self.bottom.load(Relaxed); + let t = self.top.load(Acquire); + let mut a = self.array.load(Relaxed, &guard).unwrap(); + + let size = b - t; + if size >= (a.size() as isize) - 1 { + // You won't find this code in the chase-lev deque paper. This is + // alluded to in a small footnote, however. We always free a buffer + // when growing in order to prevent leaks. + a = self.swap_buffer(a, a.resize(b, t, 1), &guard); + + // reload the bottom counter, since swap_buffer modifies it. + b = self.bottom.load(Relaxed); + } + a.put(b, data); + fence(Release); + self.bottom.store(b + 1, Relaxed); + } + + unsafe fn try_pop(&self) -> Option { + let guard = epoch::pin(); + + let b = self.bottom.load(Relaxed) - 1; + let a = self.array.load(Relaxed, &guard).unwrap(); + self.bottom.store(b, Relaxed); + fence(SeqCst); // the store to bottom must occur before loading top. + let t = self.top.load(Relaxed); + + let size = b - t; + if size >= 0 { + // non-empty case + let mut data = Some(a.get(b)); + if size == 0 { + // last element in queue, check for races. + if self.top.compare_and_swap(t, t + 1, SeqCst) != t { + // lost the race. + mem::forget(data.take()); + } + + // set the queue to a canonically empty state. + self.bottom.store(b + 1, Relaxed); + } else { + self.maybe_shrink(b, t, &guard); + } + data + } else { + // empty queue. revert the decrement of "b" and try to shrink. + // + // the original chase_lev paper uses "t" here, but the new one uses "b + 1". + // don't worry, they're the same thing: pop and steal operations will never leave + // the top counter greater than the bottom counter. After we decrement "b" at + // the beginning of this function, the lowest possible value it could hold here is "t - 1". + // That's also the only value that could cause this branch to be taken. + self.bottom.store(b + 1, Relaxed); + None + } + } + + fn steal(&self) -> Steal { + let guard = epoch::pin(); + + let t = self.top.load(Acquire); + fence(SeqCst); // top must be loaded before bottom. + let b = self.bottom.load(Acquire); + + let size = b - t; + if size <= 0 { + return Steal::Empty + } + + unsafe { + // while the paper uses a "consume" ordering here, the closest thing we have + // available is Acquire, which is strictly stronger. + let a = self.array.load(Acquire, &guard).unwrap(); + let data = a.get(t); + // we may be racing against other steals and a pop. + if self.top.compare_and_swap(t, t + 1, SeqCst) == t { + Steal::Data(data) + } else { + mem::forget(data); // someone else stole this value + Steal::Abort + } + } + } + + // potentially shrink the array. This can be called only from the worker. + unsafe fn maybe_shrink(&self, b: isize, t: isize, guard: &epoch::Guard) { + let a = self.array.load(SeqCst, guard).unwrap(); + let size = b - t; + if size < (a.size() as isize) / K && size > (1 << MIN_BITS) { + self.swap_buffer(a, a.resize(b, t, -1), guard); + } + } + + // Helper routine not mentioned in the paper which is used in growing and + // shrinking buffers to swap in a new buffer into place. + // + // As a bit of a recap, stealers can continue using buffers after this + // method has called 'unlinked' on it. The continued usage is simply a read + // followed by a forget, but we must make sure that the memory can continue + // to be read after we flag this buffer for reclamation. All stealers, + // however, have their own epoch pinned during this time so the buffer will + // just naturally be free'd once all concurrent stealers have exited. + // + // This method may only be called safely from the workers due to the way it modifies + // the array pointer. + unsafe fn swap_buffer<'a>(&self, + old: Shared<'a, Buffer>, + buf: Buffer, + guard: &'a epoch::Guard) + -> Shared<'a, Buffer> { + let newbuf = Owned::new(buf); + let newbuf = self.array.store_and_ref(newbuf, Release, &guard); + guard.unlinked(old); + + newbuf + } +} + + +impl Drop for Deque { + fn drop(&mut self) { + let guard = epoch::pin(); + + // Arc enforces that we have truly exclusive access here. + + let t = self.top.load(Relaxed); + let b = self.bottom.load(Relaxed); + let a = self.array.swap(None, Relaxed, &guard).unwrap(); + // Free whatever is leftover in the dequeue, then free the backing + // memory itself + unsafe { + for i in t..b { + drop(a.get(i)); + } + guard.unlinked(a); + } + } +} + +impl Buffer { + fn new(log_size: u32) -> Buffer { + Buffer { + storage: UnsafeCell::new(Vec::with_capacity(1 << log_size)), + log_size: log_size, + } + } + + fn size(&self) -> usize { + unsafe { (*self.storage.get()).capacity() } + } + + fn mask(&self) -> isize { + unsafe { + ((*self.storage.get()).capacity() - 1) as isize + } + } + + unsafe fn elem(&self, i: isize) -> *mut T { + (*self.storage.get()).as_mut_ptr().offset(i & self.mask()) + } + + // This does not protect against loading duplicate values of the same cell, + // nor does this clear out the contents contained within. Hence, this is a + // very unsafe method which the caller needs to treat specially in case a + // race is lost. + unsafe fn get(&self, i: isize) -> T { + ptr::read(self.elem(i)) + } + + // Unsafe because this unsafely overwrites possibly uninitialized or + // initialized data. + unsafe fn put(&self, i: isize, t: T) { + ptr::write(self.elem(i), t); + } + + // Again, unsafe because this has incredibly dubious ownership violations. + // It is assumed that this buffer is immediately dropped. + unsafe fn resize(&self, b: isize, t: isize, delta: i32) -> Buffer { + let buf = Buffer::new(((self.log_size as i32) + delta) as u32); + for i in t..b { + buf.put(i, self.get(i)); + } + return buf; + } +} + +#[cfg(test)] +mod tests { + extern crate rand; + + use super::{deque, Worker, Stealer, Steal}; + + use std::thread; + use std::sync::Arc; + use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, + AtomicUsize, ATOMIC_USIZE_INIT}; + use std::sync::atomic::Ordering::SeqCst; + + use self::rand::Rng; + + #[test] + fn smoke() { + let (mut w, s) = deque(); + assert_eq!(w.try_pop(), None); + assert_eq!(s.steal(), Steal::Empty); + w.push(1); + assert_eq!(w.try_pop(), Some(1)); + w.push(1); + assert_eq!(s.steal(), Steal::Data(1)); + w.push(1); + assert_eq!(s.clone().steal(), Steal::Data(1)); + } + + #[test] + fn stealpush() { + static AMT: isize = 100000; + let (mut w, s) = deque(); + let t = thread::spawn(move || { + let mut left = AMT; + while left > 0 { + match s.steal() { + Steal::Data(i) => { + assert_eq!(i, 1); + left -= 1; + } + Steal::Abort | Steal::Empty => {} + } + } + }); + + for _ in 0..AMT { + w.push(1); + } + + t.join().unwrap(); + } + + #[test] + fn stealpush_large() { + static AMT: isize = 100000; + let (mut w, s) = deque(); + let t = thread::spawn(move || { + let mut left = AMT; + while left > 0 { + match s.steal() { + Steal::Data((1, 10)) => { left -= 1; } + Steal::Data(..) => panic!(), + Steal::Abort | Steal::Empty => {} + } + } + }); + + for _ in 0..AMT { + w.push((1, 10)); + } + + t.join().unwrap(); + } + + fn stampede(mut w: Worker>, + s: Stealer>, + nthreads: isize, + amt: usize) { + for _ in 0..amt { + w.push(Box::new(20)); + } + let remaining = Arc::new(AtomicUsize::new(amt)); + + let threads = (0..nthreads).map(|_| { + let remaining = remaining.clone(); + let s = s.clone(); + thread::spawn(move || { + while remaining.load(SeqCst) > 0 { + match s.steal() { + Steal::Data(val) => { + if *val == 20 { + remaining.fetch_sub(1, SeqCst); + } else { + panic!() + } + } + Steal::Abort | Steal::Empty => {} + } + } + }) + }).collect::>(); + + while remaining.load(SeqCst) > 0 { + if let Some(val) = w.try_pop() { + if *val == 20 { + remaining.fetch_sub(1, SeqCst); + } else { + panic!() + } + } + } + + for thread in threads.into_iter() { + thread.join().unwrap(); + } + } + + #[test] + fn run_stampede() { + let (w, s) = deque(); + stampede(w, s, 8, 10000); + } + + #[test] + fn many_stampede() { + static AMT: usize = 4; + let threads = (0..AMT).map(|_| { + let (w, s) = deque(); + thread::spawn(|| { + stampede(w, s, 4, 10000); + }) + }).collect::>(); + + for thread in threads.into_iter() { + thread.join().unwrap(); + } + } + + #[test] + fn stress() { + static AMT: isize = 100000; + static NTHREADS: isize = 8; + static DONE: AtomicBool = ATOMIC_BOOL_INIT; + static HITS: AtomicUsize = ATOMIC_USIZE_INIT; + let (mut w, s) = deque(); + + let threads = (0..NTHREADS).map(|_| { + let s = s.clone(); + thread::spawn(move || { + loop { + match s.steal() { + Steal::Data(2) => { HITS.fetch_add(1, SeqCst); } + Steal::Data(..) => panic!(), + _ if DONE.load(SeqCst) => break, + _ => {} + } + } + }) + }).collect::>(); + + let mut rng = rand::thread_rng(); + let mut expected = 0; + while expected < AMT { + if rng.gen_range(0, 3) == 2 { + match w.try_pop() { + None => {} + Some(2) => { HITS.fetch_add(1, SeqCst); }, + Some(_) => panic!(), + } + } else { + expected += 1; + w.push(2); + } + } + + while HITS.load(SeqCst) < AMT as usize { + match w.try_pop() { + None => {} + Some(2) => { HITS.fetch_add(1, SeqCst); }, + Some(_) => panic!(), + } + } + DONE.store(true, SeqCst); + + for thread in threads.into_iter() { + thread.join().unwrap(); + } + + assert_eq!(HITS.load(SeqCst), expected as usize); + } + + #[test] + fn no_starvation() { + static AMT: isize = 10000; + static NTHREADS: isize = 4; + static DONE: AtomicBool = ATOMIC_BOOL_INIT; + let (mut w, s) = deque(); + + let (threads, hits): (Vec<_>, Vec<_>) = (0..NTHREADS).map(|_| { + let s = s.clone(); + let ctr = Arc::new(AtomicUsize::new(0)); + let ctr2 = ctr.clone(); + (thread::spawn(move || { + loop { + match s.steal() { + Steal::Data((1, 2)) => { ctr.fetch_add(1, SeqCst); } + Steal::Data(..) => panic!(), + _ if DONE.load(SeqCst) => break, + _ => {} + } + } + }), ctr2) + }).unzip(); + + let mut rng = rand::thread_rng(); + let mut myhit = false; + 'outer: loop { + for _ in 0..rng.gen_range(0, AMT) { + if !myhit && rng.gen_range(0, 3) == 2 { + match w.try_pop() { + None => {} + Some((1, 2)) => myhit = true, + Some(_) => panic!(), + } + } else { + w.push((1, 2)); + } + } + + for slot in hits.iter() { + let amt = slot.load(SeqCst); + if amt == 0 { continue 'outer; } + } + if myhit { + break + } + } + + DONE.store(true, SeqCst); + + for thread in threads.into_iter() { + thread.join().unwrap(); + } + } +} diff --git a/crossbeam-0.2.12/src/sync/mod.rs b/crossbeam-0.2.12/src/sync/mod.rs new file mode 100644 index 000000000..bdb59cfe4 --- /dev/null +++ b/crossbeam-0.2.12/src/sync/mod.rs @@ -0,0 +1,14 @@ +//! Synchronization primitives. + +pub use self::ms_queue::MsQueue; +pub use self::atomic_option::AtomicOption; +pub use self::treiber_stack::TreiberStack; +pub use self::seg_queue::SegQueue; +pub use self::arc_cell::ArcCell; + +mod atomic_option; +mod ms_queue; +mod treiber_stack; +mod seg_queue; +pub mod chase_lev; +mod arc_cell; diff --git a/crossbeam-0.2.12/src/sync/ms_queue.rs b/crossbeam-0.2.12/src/sync/ms_queue.rs new file mode 100644 index 000000000..965295b00 --- /dev/null +++ b/crossbeam-0.2.12/src/sync/ms_queue.rs @@ -0,0 +1,511 @@ +use std::sync::atomic::Ordering::{Acquire, Release, Relaxed}; +use std::sync::atomic::AtomicBool; +use std::{ptr, mem}; +use std::thread::{self, Thread}; + +use mem::epoch::{self, Atomic, Owned, Shared}; +use mem::CachePadded; + +/// A Michael-Scott lock-free queue, with support for blocking `pop`s. +/// +/// Usable with any number of producers and consumers. +// The representation here is a singly-linked list, with a sentinel +// node at the front. In general the `tail` pointer may lag behind the +// actual tail. Non-sentinal nodes are either all `Data` or all +// `Blocked` (requests for data from blocked threads). +#[derive(Debug)] +pub struct MsQueue { + head: CachePadded>>, + tail: CachePadded>>, +} + +#[derive(Debug)] +struct Node { + payload: Payload, + next: Atomic>, +} + +#[derive(Debug)] +enum Payload { + /// A node with actual data that can be popped. + Data(T), + /// A node representing a blocked request for data. + Blocked(*mut Signal), +} + +/// A blocked request for data, which includes a slot to write the data. +#[derive(Debug)] +struct Signal { + /// Thread to unpark when data is ready. + thread: Thread, + /// The actual data, when available. + data: Option, + /// Is the data ready? Needed to cope with spurious wakeups. + ready: AtomicBool, +} + +impl Node { + fn is_data(&self) -> bool { + if let Payload::Data(_) = self.payload { true } else { false } + } +} + +// Any particular `T` should never accessed concurrently, so no need +// for Sync. +unsafe impl Sync for MsQueue {} +unsafe impl Send for MsQueue {} + +impl MsQueue { + /// Create a new, empty queue. + pub fn new() -> MsQueue { + let q = MsQueue { + head: CachePadded::new(Atomic::null()), + tail: CachePadded::new(Atomic::null()), + }; + let sentinel = Owned::new(Node { + payload: Payload::Data(unsafe { mem::uninitialized() }), + next: Atomic::null(), + }); + let guard = epoch::pin(); + let sentinel = q.head.store_and_ref(sentinel, Relaxed, &guard); + q.tail.store_shared(Some(sentinel), Relaxed); + q + } + + #[inline(always)] + /// Attempt to atomically place `n` into the `next` pointer of `onto`. + /// + /// If unsuccessful, returns ownership of `n`, possibly updating + /// the queue's `tail` pointer. + fn push_internal(&self, + guard: &epoch::Guard, + onto: Shared>, + n: Owned>) + -> Result<(), Owned>> + { + // is `onto` the actual tail? + if let Some(next) = onto.next.load(Acquire, guard) { + // if not, try to "help" by moving the tail pointer forward + self.tail.cas_shared(Some(onto), Some(next), Release); + Err(n) + } else { + // looks like the actual tail; attempt to link in `n` + onto.next.cas_and_ref(None, n, Release, guard).map(|shared| { + // try to move the tail pointer forward + self.tail.cas_shared(Some(onto), Some(shared), Release); + }) + } + } + + /// Add `t` to the back of the queue, possibly waking up threads + /// blocked on `pop`. + pub fn push(&self, t: T) { + /// We may or may not need to allocate a node; once we do, + /// we cache that allocation. + enum Cache { + Data(T), + Node(Owned>), + } + + impl Cache { + /// Extract the node if cached, or allocate if not. + fn into_node(self) -> Owned> { + match self { + Cache::Data(t) => { + Owned::new(Node { + payload: Payload::Data(t), + next: Atomic::null() + }) + } + Cache::Node(n) => n + } + } + + /// Extract the data from the cache, deallocating any cached node. + fn into_data(self) -> T { + match self { + Cache::Data(t) => t, + Cache::Node(node) => { + match node.into_inner().payload { + Payload::Data(t) => t, + _ => unreachable!(), + } + } + } + } + } + + let mut cache = Cache::Data(t); // don't allocate up front + let guard = epoch::pin(); + + loop { + // We push onto the tail, so we'll start optimistically by looking + // there first. + let tail = self.tail.load(Acquire, &guard).unwrap(); + + // Is the queue in Data mode (empty queues can be viewed as either mode)? + if tail.is_data() || + self.head.load(Relaxed, &guard).unwrap().as_raw() == tail.as_raw() + { + // Attempt to push onto the `tail` snapshot; fails if + // `tail.next` has changed, which will always be the case if the + // queue has transitioned to blocking mode. + match self.push_internal(&guard, tail, cache.into_node()) { + Ok(_) => return, + Err(n) => { + // replace the cache, retry whole thing + cache = Cache::Node(n) + } + } + } else { + // Queue is in blocking mode. Attempt to unblock a thread. + let head = self.head.load(Acquire, &guard).unwrap(); + // Get a handle on the first blocked node. Racy, so queue might + // be empty or in data mode by the time we see it. + let request = head.next.load(Acquire, &guard).and_then(|next| { + match next.payload { + Payload::Blocked(signal) => Some((next, signal)), + Payload::Data(_) => None, + } + }); + if let Some((blocked_node, signal)) = request { + // race to dequeue the node + if self.head.cas_shared(Some(head), Some(blocked_node), Release) { + unsafe { + // signal the thread + (*signal).data = Some(cache.into_data()); + (*signal).ready.store(true, Relaxed); + (*signal).thread.unpark(); + guard.unlinked(head); + return; + } + } + } + } + } + } + + #[inline(always)] + // Attempt to pop a data node. `Ok(None)` if queue is empty or in blocking + // mode; `Err(())` if lost race to pop. + fn pop_internal(&self, guard: &epoch::Guard) -> Result, ()> { + let head = self.head.load(Acquire, guard).unwrap(); + if let Some(next) = head.next.load(Acquire, guard) { + if let Payload::Data(ref t) = next.payload { + unsafe { + if self.head.cas_shared(Some(head), Some(next), Release) { + guard.unlinked(head); + Ok(Some(ptr::read(t))) + } else { + Err(()) + } + } + } else { + Ok(None) + } + } else { + Ok(None) + } + } + + /// Check if this queue is empty. + pub fn is_empty(&self) -> bool { + let guard = epoch::pin(); + let head = self.head.load(Acquire, &guard).unwrap(); + + if let Some(next) = head.next.load(Acquire, &guard) { + if let Payload::Data(_) = next.payload { + false + } else { + true + } + } else { + true + } + } + + /// Attempt to dequeue from the front. + /// + /// Returns `None` if the queue is observed to be empty. + pub fn try_pop(&self) -> Option { + let guard = epoch::pin(); + loop { + if let Ok(r) = self.pop_internal(&guard) { + return r; + } + } + } + + /// Dequeue an element from the front of the queue, blocking if the queue is + /// empty. + pub fn pop(&self) -> T { + let guard = epoch::pin(); + + // Fast path: keep retrying until we observe that the queue has no data, + // avoiding the allocation of a blocked node. + loop { + match self.pop_internal(&guard) { + Ok(Some(r)) => { + return r; + } + Ok(None) => { + break; + } + Err(()) => {} + } + } + + // The signal gets to live on the stack, since this stack frame will be + // blocked until receiving the signal. + let mut signal = Signal { + thread: thread::current(), + data: None, + ready: AtomicBool::new(false), + }; + + // Go ahead and allocate the blocked node; chances are, we'll need it. + let mut node = Owned::new(Node { + payload: Payload::Blocked(&mut signal), + next: Atomic::null(), + }); + + loop { + // try a normal pop + if let Ok(Some(r)) = self.pop_internal(&guard) { + return r; + } + + // At this point, we believe the queue is empty/blocked. + // Snapshot the tail, onto which we want to push a blocked node. + let tail = self.tail.load(Relaxed, &guard).unwrap(); + + // Double-check that we're in blocking mode + if tail.is_data() { + // The current tail is in data mode, so we probably need to abort. + // BUT, it might be the sentinel, so check for that first. + let head = self.head.load(Relaxed, &guard).unwrap(); + if tail.is_data() && tail.as_raw() != head.as_raw() { continue; } + } + + // At this point, the tail snapshot is either a blocked node deep in + // the queue, the sentinel, or no longer accessible from the queue. + // In *ALL* of these cases, if we succeed in pushing onto the + // snapshot, we know we are maintaining the core invariant: all + // reachable, non-sentinel nodes have the same payload mode, in this + // case, blocked. + match self.push_internal(&guard, tail, node) { + Ok(()) => { + while !signal.ready.load(Relaxed) { + thread::park(); + } + return signal.data.unwrap(); + } + Err(n) => { + node = n; + } + } + } + } +} + +#[cfg(test)] +mod test { + const CONC_COUNT: i64 = 1000000; + + use scope; + use super::*; + + #[test] + fn push_try_pop_1() { + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + q.push(37); + assert!(!q.is_empty()); + assert_eq!(q.try_pop(), Some(37)); + assert!(q.is_empty()); + } + + #[test] + fn push_try_pop_2() { + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + q.push(37); + q.push(48); + assert_eq!(q.try_pop(), Some(37)); + assert!(!q.is_empty()); + assert_eq!(q.try_pop(), Some(48)); + assert!(q.is_empty()); + } + + #[test] + fn push_try_pop_many_seq() { + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + for i in 0..200 { + q.push(i) + } + assert!(!q.is_empty()); + for i in 0..200 { + assert_eq!(q.try_pop(), Some(i)); + } + assert!(q.is_empty()); + } + + #[test] + fn push_pop_1() { + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + q.push(37); + assert!(!q.is_empty()); + assert_eq!(q.pop(), 37); + assert!(q.is_empty()); + } + + #[test] + fn push_pop_2() { + let q: MsQueue = MsQueue::new(); + q.push(37); + q.push(48); + assert_eq!(q.pop(), 37); + assert_eq!(q.pop(), 48); + } + + #[test] + fn push_pop_many_seq() { + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + for i in 0..200 { + q.push(i) + } + assert!(!q.is_empty()); + for i in 0..200 { + assert_eq!(q.pop(), i); + } + assert!(q.is_empty()); + } + + #[test] + fn push_try_pop_many_spsc() { + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + + scope(|scope| { + scope.spawn(|| { + let mut next = 0; + + while next < CONC_COUNT { + if let Some(elem) = q.try_pop() { + assert_eq!(elem, next); + next += 1; + } + } + }); + + for i in 0..CONC_COUNT { + q.push(i) + } + }); + } + + #[test] + fn push_try_pop_many_spmc() { + fn recv(_t: i32, q: &MsQueue) { + let mut cur = -1; + for _i in 0..CONC_COUNT { + if let Some(elem) = q.try_pop() { + assert!(elem > cur); + cur = elem; + + if cur == CONC_COUNT - 1 { break } + } + } + } + + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + let qr = &q; + scope(|scope| { + for i in 0..3 { + scope.spawn(move || recv(i, qr)); + } + + scope.spawn(|| { + for i in 0..CONC_COUNT { + q.push(i); + } + }) + }); + } + + #[test] + fn push_try_pop_many_mpmc() { + enum LR { Left(i64), Right(i64) } + + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + + scope(|scope| { + for _t in 0..2 { + scope.spawn(|| { + for i in CONC_COUNT-1..CONC_COUNT { + q.push(LR::Left(i)) + } + }); + scope.spawn(|| { + for i in CONC_COUNT-1..CONC_COUNT { + q.push(LR::Right(i)) + } + }); + scope.spawn(|| { + let mut vl = vec![]; + let mut vr = vec![]; + for _i in 0..CONC_COUNT { + match q.try_pop() { + Some(LR::Left(x)) => vl.push(x), + Some(LR::Right(x)) => vr.push(x), + _ => {} + } + } + + let mut vl2 = vl.clone(); + let mut vr2 = vr.clone(); + vl2.sort(); + vr2.sort(); + + assert_eq!(vl, vl2); + assert_eq!(vr, vr2); + }); + } + }); + } + + #[test] + fn push_pop_many_spsc() { + let q: MsQueue = MsQueue::new(); + + scope(|scope| { + scope.spawn(|| { + let mut next = 0; + while next < CONC_COUNT { + assert_eq!(q.pop(), next); + next += 1; + } + }); + + for i in 0..CONC_COUNT { + q.push(i) + } + }); + assert!(q.is_empty()); + } + + #[test] + fn is_empty_dont_pop() { + let q: MsQueue = MsQueue::new(); + q.push(20); + q.push(20); + assert!(!q.is_empty()); + assert!(!q.is_empty()); + assert!(q.try_pop().is_some()); + } +} diff --git a/crossbeam-0.2.12/src/sync/seg_queue.rs b/crossbeam-0.2.12/src/sync/seg_queue.rs new file mode 100644 index 000000000..edc6568ac --- /dev/null +++ b/crossbeam-0.2.12/src/sync/seg_queue.rs @@ -0,0 +1,251 @@ +use std::sync::atomic::Ordering::{Acquire, Release, Relaxed}; +use std::sync::atomic::{AtomicBool, AtomicUsize}; +use std::fmt; +use std::{ptr, mem}; +use std::cmp; +use std::cell::UnsafeCell; + +use mem::epoch::{self, Atomic, Owned}; + +const SEG_SIZE: usize = 32; + +/// A Michael-Scott queue that allocates "segments" (arrays of nodes) +/// for efficiency. +/// +/// Usable with any number of producers and consumers. +#[derive(Debug)] +pub struct SegQueue { + head: Atomic>, + tail: Atomic>, +} + +struct Segment { + low: AtomicUsize, + data: [UnsafeCell<(T, AtomicBool)>; SEG_SIZE], + high: AtomicUsize, + next: Atomic>, +} + +impl fmt::Debug for Segment { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Segment {{ ... }}") + } +} + +unsafe impl Sync for Segment {} + +impl Segment { + fn new() -> Segment { + let rqueue = Segment { + data: unsafe { mem::uninitialized() }, + low: AtomicUsize::new(0), + high: AtomicUsize::new(0), + next: Atomic::null(), + }; + for val in rqueue.data.iter() { + unsafe { + (*val.get()).1 = AtomicBool::new(false); + } + } + rqueue + } +} + +impl SegQueue { + /// Create a new, empty queue. + pub fn new() -> SegQueue { + let q = SegQueue { + head: Atomic::null(), + tail: Atomic::null(), + }; + let sentinel = Owned::new(Segment::new()); + let guard = epoch::pin(); + let sentinel = q.head.store_and_ref(sentinel, Relaxed, &guard); + q.tail.store_shared(Some(sentinel), Relaxed); + q + } + + /// Add `t` to the back of the queue. + pub fn push(&self, t: T) { + let guard = epoch::pin(); + loop { + let tail = self.tail.load(Acquire, &guard).unwrap(); + if tail.high.load(Relaxed) >= SEG_SIZE { continue } + let i = tail.high.fetch_add(1, Relaxed); + unsafe { + if i < SEG_SIZE { + let cell = (*tail).data.get_unchecked(i).get(); + ptr::write(&mut (*cell).0, t); + (*cell).1.store(true, Release); + + if i + 1 == SEG_SIZE { + let tail = tail.next.store_and_ref(Owned::new(Segment::new()), Release, &guard); + self.tail.store_shared(Some(tail), Release); + } + + return + } + } + } + } + + /// Attempt to dequeue from the front. + /// + /// Returns `None` if the queue is observed to be empty. + pub fn try_pop(&self) -> Option { + let guard = epoch::pin(); + loop { + let head = self.head.load(Acquire, &guard).unwrap(); + loop { + let low = head.low.load(Relaxed); + if low >= cmp::min(head.high.load(Relaxed), SEG_SIZE) { break } + if head.low.compare_and_swap(low, low+1, Relaxed) == low { + unsafe { + let cell = (*head).data.get_unchecked(low).get(); + loop { + if (*cell).1.load(Acquire) { break } + } + if low + 1 == SEG_SIZE { + loop { + if let Some(next) = head.next.load(Acquire, &guard) { + self.head.store_shared(Some(next), Release); + guard.unlinked(head); + break + } + } + } + return Some(ptr::read(&(*cell).0)) + } + } + } + if head.next.load(Relaxed, &guard).is_none() { return None } + } + } +} + +#[cfg(test)] +mod test { + const CONC_COUNT: i64 = 1000000; + + use scope; + use super::*; + + #[test] + fn push_pop_1() { + let q: SegQueue = SegQueue::new(); + q.push(37); + assert_eq!(q.try_pop(), Some(37)); + } + + #[test] + fn push_pop_2() { + let q: SegQueue = SegQueue::new(); + q.push(37); + q.push(48); + assert_eq!(q.try_pop(), Some(37)); + assert_eq!(q.try_pop(), Some(48)); + } + + #[test] + fn push_pop_many_seq() { + let q: SegQueue = SegQueue::new(); + for i in 0..200 { + q.push(i) + } + for i in 0..200 { + assert_eq!(q.try_pop(), Some(i)); + } + } + + #[test] + fn push_pop_many_spsc() { + let q: SegQueue = SegQueue::new(); + + scope(|scope| { + scope.spawn(|| { + let mut next = 0; + + while next < CONC_COUNT { + if let Some(elem) = q.try_pop() { + assert_eq!(elem, next); + next += 1; + } + } + }); + + for i in 0..CONC_COUNT { + q.push(i) + } + }); + } + + #[test] + fn push_pop_many_spmc() { + fn recv(_t: i32, q: &SegQueue) { + let mut cur = -1; + for _i in 0..CONC_COUNT { + if let Some(elem) = q.try_pop() { + assert!(elem > cur); + cur = elem; + + if cur == CONC_COUNT - 1 { break } + } + } + } + + let q: SegQueue = SegQueue::new(); + let qr = &q; + scope(|scope| { + for i in 0..3 { + scope.spawn(move || recv(i, qr)); + } + + scope.spawn(|| { + for i in 0..CONC_COUNT { + q.push(i); + } + }) + }); + } + + #[test] + fn push_pop_many_mpmc() { + enum LR { Left(i64), Right(i64) } + + let q: SegQueue = SegQueue::new(); + + scope(|scope| { + for _t in 0..2 { + scope.spawn(|| { + for i in CONC_COUNT-1..CONC_COUNT { + q.push(LR::Left(i)) + } + }); + scope.spawn(|| { + for i in CONC_COUNT-1..CONC_COUNT { + q.push(LR::Right(i)) + } + }); + scope.spawn(|| { + let mut vl = vec![]; + let mut vr = vec![]; + for _i in 0..CONC_COUNT { + match q.try_pop() { + Some(LR::Left(x)) => vl.push(x), + Some(LR::Right(x)) => vr.push(x), + _ => {} + } + } + + let mut vl2 = vl.clone(); + let mut vr2 = vr.clone(); + vl2.sort(); + vr2.sort(); + + assert_eq!(vl, vl2); + assert_eq!(vr, vr2); + }); + } + }); + } +} diff --git a/crossbeam-0.2.12/src/sync/treiber_stack.rs b/crossbeam-0.2.12/src/sync/treiber_stack.rs new file mode 100644 index 000000000..213bf683b --- /dev/null +++ b/crossbeam-0.2.12/src/sync/treiber_stack.rs @@ -0,0 +1,98 @@ +use std::sync::atomic::Ordering::{Acquire, Release, Relaxed}; +use std::ptr; + +use mem::epoch::{self, Atomic, Owned}; + +/// Treiber's lock-free stack. +/// +/// Usable with any number of producers and consumers. +#[derive(Debug)] +pub struct TreiberStack { + head: Atomic>, +} + +#[derive(Debug)] +struct Node { + data: T, + next: Atomic>, +} + +impl TreiberStack { + /// Create a new, empty stack. + pub fn new() -> TreiberStack { + TreiberStack { head: Atomic::null() } + } + + /// Push `t` on top of the stack. + pub fn push(&self, t: T) { + let mut n = Owned::new(Node { + data: t, + next: Atomic::null(), + }); + let guard = epoch::pin(); + loop { + let head = self.head.load(Relaxed, &guard); + n.next.store_shared(head, Relaxed); + match self.head.cas_and_ref(head, n, Release, &guard) { + Ok(_) => break, + Err(owned) => n = owned, + } + } + } + + /// Attempt to pop the top element of the stack. + /// **Deprecated method**, use try_pop + /// + /// Returns `None` if the stack is observed to be empty. + #[cfg_attr(any(feature="beta", feature="nightly"), deprecated(note="The pop method has been renamed to try_pop for consistency with other collections."))] + pub fn pop(&self) -> Option { + self.try_pop() + } + + /// Attempt to pop the top element of the stack. + /// + /// Returns `None` if the stack is observed to be empty. + pub fn try_pop(&self) -> Option { + let guard = epoch::pin(); + loop { + match self.head.load(Acquire, &guard) { + Some(head) => { + let next = head.next.load(Relaxed, &guard); + if self.head.cas_shared(Some(head), next, Release) { + unsafe { + guard.unlinked(head); + return Some(ptr::read(&(*head).data)); + } + } + } + None => return None, + } + } + } + + /// Check if this queue is empty. + pub fn is_empty(&self) -> bool { + let guard = epoch::pin(); + self.head.load(Acquire, &guard).is_none() + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn is_empty() { + let q: TreiberStack = TreiberStack::new(); + assert!(q.is_empty()); + q.push(20); + q.push(20); + assert!(!q.is_empty()); + assert!(!q.is_empty()); + assert!(q.try_pop().is_some()); + assert!(q.try_pop().is_some()); + assert!(q.is_empty()); + q.push(25); + assert!(!q.is_empty()); + } +} diff --git a/crossbeam-0.3.2/.cargo-checksum.json b/crossbeam-0.3.2/.cargo-checksum.json new file mode 100644 index 000000000..d224d9446 --- /dev/null +++ b/crossbeam-0.3.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19"} \ No newline at end of file diff --git a/crossbeam-0.3.2/.travis.yml b/crossbeam-0.3.2/.travis.yml new file mode 100644 index 000000000..7e692baaf --- /dev/null +++ b/crossbeam-0.3.2/.travis.yml @@ -0,0 +1,36 @@ +language: rust +# necessary for `travis-cargo coveralls --no-sudo` +addons: + apt: + packages: + - libcurl4-openssl-dev + - libelf-dev + - libdw-dev + +# run builds for all the trains (and more) +rust: + - nightly + - beta + - stable + +# load travis-cargo +before_script: + - | + pip install 'travis-cargo<0.2' --user && + export PATH=$HOME/.local/bin:$PATH + +# the main build +script: + - | + travis-cargo build && + travis-cargo test && + travis-cargo test -- --release && + travis-cargo run -- --bin bench --release && + travis-cargo --only stable doc +env: + global: + # override the default `--features unstable` used for the nightly branch (optional) + - TRAVIS_CARGO_NIGHTLY_FEATURE=nightly +notifications: + email: + on_success: never diff --git a/crossbeam-0.3.2/CHANGELOG.md b/crossbeam-0.3.2/CHANGELOG.md new file mode 100644 index 000000000..adea6000e --- /dev/null +++ b/crossbeam-0.3.2/CHANGELOG.md @@ -0,0 +1,22 @@ +# Version 0.3 + +- Introduced `ScopedThreadBuilder` with the ability to name threads and set stack size +- `Worker` methods in the Chase-Lev deque don't require mutable access anymore +- Fixed a bug when unblocking `pop()` in `MsQueue` +- Implemented `Drop` for `MsQueue`, `SegQueue`, and `TreiberStack` +- Implemented `Default` for `TreiberStack` +- Added `is_empty` to `SegQueue` +- Renamed `mem::epoch` to `epoch` +- Other bug fixes + +# Version 0.2 + +- Changed existing non-blocking `pop` methods to `try_pop` +- Added blocking `pop` support to Michael-Scott queue +- Added Chase-Lev work-stealing deque + +# Version 0.1 + +- Added [epoch-based memory management](http://aturon.github.io/blog/2015/08/27/epoch/) +- Added Michael-Scott queue +- Added Segmented array queue diff --git a/crossbeam-0.3.2/Cargo.toml b/crossbeam-0.3.2/Cargo.toml new file mode 100644 index 000000000..757789599 --- /dev/null +++ b/crossbeam-0.3.2/Cargo.toml @@ -0,0 +1,27 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "crossbeam" +version = "0.3.2" +authors = ["Aaron Turon "] +description = "Support for lock-free data structures, synchronizers, and parallel programming" +documentation = "https://docs.rs/crossbeam" +readme = "README.md" +categories = ["concurrency", "data-structures"] +license = "Apache-2.0/MIT" +repository = "https://github.com/crossbeam-rs/crossbeam" +[dev-dependencies.rand] +version = "0.3" + +[features] +nightly = [] diff --git a/crossbeam-0.3.2/LICENSE-APACHE b/crossbeam-0.3.2/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/crossbeam-0.3.2/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/crossbeam-0.3.2/LICENSE-MIT b/crossbeam-0.3.2/LICENSE-MIT new file mode 100644 index 000000000..e69282e38 --- /dev/null +++ b/crossbeam-0.3.2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/crossbeam-0.3.2/README.md b/crossbeam-0.3.2/README.md new file mode 100644 index 000000000..d424d1172 --- /dev/null +++ b/crossbeam-0.3.2/README.md @@ -0,0 +1,46 @@ +# Notice + +This crate is outdated. The Crossbeam project is currently in a transition +period. We are rewriting the epoch garbage collector, as well as several +other utilities and adding new structures. To follow the progress, please +take a look at other crates in the project [here](https://github.com/crossbeam-rs). +When the transition is complete, this crate will be updated to use the new code. + +# Crossbeam: support for concurrent and parallel programming + +[![Build Status](https://travis-ci.org/crossbeam-rs/crossbeam.svg?branch=master)](https://travis-ci.org/crossbeam-rs/crossbeam) + + +This crate is an early work in progress. The focus for the moment is +concurrency: + +- **Non-blocking data structures**. These data structures allow for high +performance, highly-concurrent access, much superior to wrapping with a +`Mutex`. Ultimately the goal is to include stacks, queues, deques, bags, sets +and maps. + +- **Memory management**. Because non-blocking data structures avoid global +synchronization, it is not easy to tell when internal data can be safely +freed. The `epoch` module provides generic, easy to use, and high-performance APIs +for managing memory in these cases. + +- **Synchronization**. The standard library provides a few synchronization +primitives (locks, barriers, etc) but this crate seeks to expand that set to +include more advanced/niche primitives, as well as userspace alternatives. + +- **Scoped thread API**. Finally, the crate provides a "scoped" thread API, +making it possible to spawn threads that share stack data with their parents. + +# Usage + +To use Crossbeam, add this to your `Cargo.toml`: + +```toml +[dependencies] +crossbeam = "0.3.0" +``` + +For examples of what Crossbeam is capable of, see the +[documentation][docs]. + +[docs]: https://docs.rs/crossbeam/ diff --git a/crossbeam-0.3.2/src/bin/bench.rs b/crossbeam-0.3.2/src/bin/bench.rs new file mode 100644 index 000000000..74090e8f3 --- /dev/null +++ b/crossbeam-0.3.2/src/bin/bench.rs @@ -0,0 +1,159 @@ +extern crate crossbeam; + +use std::collections::VecDeque; +use std::sync::Mutex; +use std::sync::mpsc::channel; +use std::time::Duration; + +use crossbeam::scope; +use crossbeam::sync::MsQueue; +use crossbeam::sync::SegQueue; + +use extra_impls::mpsc_queue::Queue as MpscQueue; + +mod extra_impls; + +const COUNT: u64 = 10000000; +const THREADS: u64 = 2; + +fn time(f: F) -> Duration { + let start = ::std::time::Instant::now(); + f(); + start.elapsed() +} + +fn nanos(d: Duration) -> f64 { + d.as_secs() as f64 * 1000000000f64 + (d.subsec_nanos() as f64) +} + +trait Queue { + fn push(&self, T); + fn try_pop(&self) -> Option; +} + +impl Queue for MsQueue { + fn push(&self, t: T) { self.push(t) } + fn try_pop(&self) -> Option { self.try_pop() } +} + +impl Queue for SegQueue { + fn push(&self, t: T) { self.push(t) } + fn try_pop(&self) -> Option { self.try_pop() } +} + +impl Queue for MpscQueue { + fn push(&self, t: T) { self.push(t) } + fn try_pop(&self) -> Option { + use extra_impls::mpsc_queue::*; + + loop { + match self.pop() { + Data(t) => return Some(t), + Empty => return None, + Inconsistent => (), + } + } + } +} + +impl Queue for Mutex> { + fn push(&self, t: T) { self.lock().unwrap().push_back(t) } + fn try_pop(&self) -> Option { self.lock().unwrap().pop_front() } +} + +fn bench_queue_mpsc + Sync>(q: Q) -> f64 { + let d = time(|| { + scope(|scope| { + for _i in 0..THREADS { + let qr = &q; + scope.spawn(move || { + for x in 0..COUNT { + let _ = qr.push(x); + } + }); + } + + let mut count = 0; + while count < COUNT*THREADS { + if q.try_pop().is_some() { + count += 1; + } + } + }); + }); + + nanos(d) / ((COUNT * THREADS) as f64) +} + +fn bench_queue_mpmc + Sync>(q: Q) -> f64 { + use std::sync::atomic::AtomicUsize; + use std::sync::atomic::Ordering::Relaxed; + + let prod_count = AtomicUsize::new(0); + + let d = time(|| { + scope(|scope| { + for _i in 0..THREADS { + let qr = &q; + let pcr = &prod_count; + scope.spawn(move || { + for _x in 0..COUNT { + qr.push(true); + } + if pcr.fetch_add(1, Relaxed) == (THREADS as usize) - 1 { + for _x in 0..THREADS { + qr.push(false) + } + } + }); + scope.spawn(move || { + loop { + if let Some(false) = qr.try_pop() { break } + } + }); + } + + + }); + }); + + nanos(d) / ((COUNT * THREADS) as f64) +} + +fn bench_chan_mpsc() -> f64 { + let (tx, rx) = channel(); + + let d = time(|| { + scope(|scope| { + for _i in 0..THREADS { + let my_tx = tx.clone(); + + scope.spawn(move || { + for x in 0..COUNT { + let _ = my_tx.send(x); + } + }); + } + + for _i in 0..COUNT*THREADS { + let _ = rx.recv().unwrap(); + } + }); + }); + + nanos(d) / ((COUNT * THREADS) as f64) +} + +fn main() { + println!("MSQ mpsc: {}", bench_queue_mpsc(MsQueue::new())); + println!("chan mpsc: {}", bench_chan_mpsc()); + println!("mpsc mpsc: {}", bench_queue_mpsc(MpscQueue::new())); + println!("Seg mpsc: {}", bench_queue_mpsc(SegQueue::new())); + + println!("MSQ mpmc: {}", bench_queue_mpmc(MsQueue::new())); + println!("Seg mpmc: {}", bench_queue_mpmc(SegQueue::new())); + +// println!("queue_mpsc: {}", bench_queue_mpsc()); +// println!("queue_mpmc: {}", bench_queue_mpmc()); +// println!("mutex_mpmc: {}", bench_mutex_mpmc()); +} diff --git a/crossbeam-0.3.2/src/bin/extra_impls/mod.rs b/crossbeam-0.3.2/src/bin/extra_impls/mod.rs new file mode 100644 index 000000000..485946a9f --- /dev/null +++ b/crossbeam-0.3.2/src/bin/extra_impls/mod.rs @@ -0,0 +1 @@ +pub mod mpsc_queue; diff --git a/crossbeam-0.3.2/src/bin/extra_impls/mpsc_queue.rs b/crossbeam-0.3.2/src/bin/extra_impls/mpsc_queue.rs new file mode 100644 index 000000000..3bff5dc6c --- /dev/null +++ b/crossbeam-0.3.2/src/bin/extra_impls/mpsc_queue.rs @@ -0,0 +1,155 @@ +/* Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of Dmitry Vyukov. + */ + +//! A mostly lock-free multi-producer, single consumer queue. +//! +//! This module contains an implementation of a concurrent MPSC queue. This +//! queue can be used to share data between threads, and is also used as the +//! building block of channels in rust. +//! +//! Note that the current implementation of this queue has a caveat of the `pop` +//! method, and see the method for more information about it. Due to this +//! caveat, this queue may not be appropriate for all use-cases. + +// http://www.1024cores.net/home/lock-free-algorithms +// /queues/non-intrusive-mpsc-node-based-queue + +pub use self::PopResult::*; + +use std::fmt; +use std::ptr; +use std::cell::UnsafeCell; + +use std::sync::atomic::{AtomicPtr, Ordering}; + +/// A result of the `pop` function. +#[derive(Debug)] +pub enum PopResult { + /// Some data has been popped + Data(T), + /// The queue is empty + Empty, + /// The queue is in an inconsistent state. Popping data should succeed, but + /// some pushers have yet to make enough progress in order allow a pop to + /// succeed. It is recommended that a pop() occur "in the near future" in + /// order to see if the sender has made progress or not + Inconsistent, +} + +#[derive(Debug)] +struct Node { + next: AtomicPtr>, + value: Option, +} + +/// The multi-producer single-consumer structure. This is not cloneable, but it +/// may be safely shared so long as it is guaranteed that there is only one +/// popper at a time (many pushers are allowed). +pub struct Queue { + head: AtomicPtr>, + tail: UnsafeCell<*mut Node>, +} + +impl fmt::Debug for Queue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Queue {{ ... }}") + } +} + +unsafe impl Send for Queue { } +unsafe impl Sync for Queue { } + +impl Node { + unsafe fn new(v: Option) -> *mut Node { + Box::into_raw(Box::new(Node { + next: AtomicPtr::new(ptr::null_mut()), + value: v, + })) + } +} + +impl Queue { + /// Creates a new queue that is safe to share among multiple producers and + /// one consumer. + pub fn new() -> Queue { + let stub = unsafe { Node::new(None) }; + Queue { + head: AtomicPtr::new(stub), + tail: UnsafeCell::new(stub), + } + } + + /// Pushes a new value onto this queue. + pub fn push(&self, t: T) { + unsafe { + let n = Node::new(Some(t)); + let prev = self.head.swap(n, Ordering::AcqRel); + (*prev).next.store(n, Ordering::Release); + } + } + + /// Pops some data from this queue. + /// + /// Note that the current implementation means that this function cannot + /// return `Option`. It is possible for this queue to be in an + /// inconsistent state where many pushes have succeeded and completely + /// finished, but pops cannot return `Some(t)`. This inconsistent state + /// happens when a pusher is pre-empted at an inopportune moment. + /// + /// This inconsistent state means that this queue does indeed have data, but + /// it does not currently have access to it at this time. + pub fn pop(&self) -> PopResult { + unsafe { + let tail = *self.tail.get(); + let next = (*tail).next.load(Ordering::Acquire); + + if !next.is_null() { + *self.tail.get() = next; + assert!((*tail).value.is_none()); + assert!((*next).value.is_some()); + let ret = (*next).value.take().unwrap(); + let _ = Box::from_raw(tail); + return Data(ret); + } + + if self.head.load(Ordering::Acquire) == tail {Empty} else {Inconsistent} + } + } +} + +impl Drop for Queue { + fn drop(&mut self) { + unsafe { + let mut cur = *self.tail.get(); + while !cur.is_null() { + let next = (*cur).next.load(Ordering::Relaxed); + let _ = Box::from_raw(cur); + cur = next; + } + } + } +} diff --git a/crossbeam-0.3.2/src/bin/stress-msq.rs b/crossbeam-0.3.2/src/bin/stress-msq.rs new file mode 100644 index 000000000..7de749642 --- /dev/null +++ b/crossbeam-0.3.2/src/bin/stress-msq.rs @@ -0,0 +1,36 @@ +extern crate crossbeam; + +use crossbeam::sync::MsQueue; +use crossbeam::scope; + +use std::sync::Arc; + +const DUP: usize = 4; +const THREADS: u32 = 2; +const COUNT: u64 = 100000; + +fn main() { + scope(|s| { + for _i in 0..DUP { + let q = Arc::new(MsQueue::new()); + let qs = q.clone(); + + s.spawn(move || { + for i in 1..COUNT { qs.push(i) } + }); + + for _i in 0..THREADS { + let qr = q.clone(); + s.spawn(move || { + let mut cur: u64 = 0; + for _j in 0..COUNT { + if let Some(new) = qr.try_pop() { + assert!(new > cur); + cur = new; + } + } + }); + } + } + }); +} diff --git a/crossbeam-0.3.2/src/cache_padded.rs b/crossbeam-0.3.2/src/cache_padded.rs new file mode 100644 index 000000000..ae6a3c58e --- /dev/null +++ b/crossbeam-0.3.2/src/cache_padded.rs @@ -0,0 +1,164 @@ +use std::marker; +use std::cell::UnsafeCell; +use std::fmt; +use std::mem; +use std::ptr; +use std::ops::{Deref, DerefMut}; + +// For now, treat this as an arch-independent constant. +const CACHE_LINE: usize = 32; + +#[cfg_attr(feature = "nightly", + repr(simd))] +#[derive(Debug)] +struct Padding(u64, u64, u64, u64); + +/// Pad `T` to the length of a cacheline. +/// +/// Sometimes concurrent programming requires a piece of data to be padded out +/// to the size of a cacheline to avoid "false sharing": cachelines being +/// invalidated due to unrelated concurrent activity. Use the `CachePadded` type +/// when you want to *avoid* cache locality. +/// +/// At the moment, cache lines are assumed to be 32 * sizeof(usize) on all +/// architectures. +/// +/// **Warning**: the wrapped data is never dropped; move out using `ptr::read` +/// if you need to run dtors. +pub struct CachePadded { + data: UnsafeCell<[usize; CACHE_LINE]>, + _marker: ([Padding; 0], marker::PhantomData), +} + +impl fmt::Debug for CachePadded { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "CachePadded {{ ... }}") + } +} + +unsafe impl Send for CachePadded {} +unsafe impl Sync for CachePadded {} + +#[cfg(not(feature = "nightly"))] +macro_rules! declare_zeros_valid { + () => { + /// Types for which mem::zeroed() is safe. + /// + /// If a type `T: ZerosValid`, then a sequence of zeros the size of `T` must be + /// a valid member of the type `T`. + pub unsafe trait ZerosValid {} + } +} + +#[cfg(feature = "nightly")] +macro_rules! declare_zeros_valid { + () => { + /// Types for which mem::zeroed() is safe. + /// + /// If a type `T: ZerosValid`, then a sequence of zeros the size of `T` must be + /// a valid member of the type `T`. + pub unsafe auto trait ZerosValid {} + } +} + +declare_zeros_valid!(); + +macro_rules! zeros_valid { ($( $T:ty )*) => ($( + unsafe impl ZerosValid for $T {} +)*)} + +zeros_valid!(u8 u16 u32 u64 usize); +zeros_valid!(i8 i16 i32 i64 isize); + +unsafe impl ZerosValid for ::std::sync::atomic::AtomicUsize {} +unsafe impl ZerosValid for ::std::sync::atomic::AtomicPtr {} + +impl CachePadded { + /// A const fn equivalent to mem::zeroed(). + #[cfg(not(feature = "nightly"))] + pub fn zeroed() -> CachePadded { + CachePadded { + data: UnsafeCell::new(([0; CACHE_LINE])), + _marker: ([], marker::PhantomData), + } + } + + /// A const fn equivalent to mem::zeroed(). + #[cfg(feature = "nightly")] + pub const fn zeroed() -> CachePadded { + CachePadded { + data: UnsafeCell::new(([0; CACHE_LINE])), + _marker: ([], marker::PhantomData), + } + } +} + +#[inline] +/// Assert that the size and alignment of `T` are consistent with `CachePadded`. +fn assert_valid() { + assert!(mem::size_of::() <= mem::size_of::>()); + assert!(mem::align_of::() <= mem::align_of::>()); +} + +impl CachePadded { + /// Wrap `t` with cacheline padding. + /// + /// **Warning**: the wrapped data is never dropped; move out using + /// `ptr:read` if you need to run dtors. + pub fn new(t: T) -> CachePadded { + assert_valid::(); + let ret = CachePadded { + data: UnsafeCell::new(([0; CACHE_LINE])), + _marker: ([], marker::PhantomData), + }; + unsafe { + let p: *mut T = mem::transmute(&ret.data); + ptr::write(p, t); + } + ret + } +} + +impl Deref for CachePadded { + type Target = T; + fn deref(&self) -> &T { + assert_valid::(); + unsafe { mem::transmute(&self.data) } + } +} + +impl DerefMut for CachePadded { + fn deref_mut(&mut self) -> &mut T { + assert_valid::(); + unsafe { mem::transmute(&mut self.data) } + } +} + +// FIXME: support Drop by pulling out a version usable for statics +/* +impl Drop for CachePadded { + fn drop(&mut self) { + assert_valid::(); + let p: *mut T = mem::transmute(&self.data); + mem::drop(ptr::read(p)); + } +} +*/ + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn cache_padded_store_u64() { + let x: CachePadded = CachePadded::new(17); + assert_eq!(*x, 17); + } + + #[test] + fn cache_padded_store_pair() { + let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37)); + assert_eq!(x.0, 17); + assert_eq!(x.1, 37); + } +} diff --git a/crossbeam-0.3.2/src/epoch/atomic.rs b/crossbeam-0.3.2/src/epoch/atomic.rs new file mode 100644 index 000000000..1d8e7cec5 --- /dev/null +++ b/crossbeam-0.3.2/src/epoch/atomic.rs @@ -0,0 +1,181 @@ +use std::marker::PhantomData; +use std::mem; +use std::ptr; +use std::sync::atomic::{self, Ordering}; + +use super::{Owned, Shared, Guard}; + +/// Like `std::sync::atomic::AtomicPtr`. +/// +/// Provides atomic access to a (nullable) pointer of type `T`, interfacing with +/// the `Owned` and `Shared` types. +#[derive(Debug)] +pub struct Atomic { + ptr: atomic::AtomicPtr, + _marker: PhantomData<*const ()>, +} + +unsafe impl Send for Atomic {} +unsafe impl Sync for Atomic {} + +fn opt_shared_into_raw(val: Option>) -> *mut T { + val.map(|p| p.as_raw()).unwrap_or(ptr::null_mut()) +} + +fn opt_owned_as_raw(val: &Option>) -> *mut T { + val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut()) +} + +fn opt_owned_into_raw(val: Option>) -> *mut T { + let ptr = val.as_ref().map(Owned::as_raw).unwrap_or(ptr::null_mut()); + mem::forget(val); + ptr +} + +impl Atomic { + /// Create a new, null atomic pointer. + #[cfg(feature = "nightly")] + pub const fn null() -> Atomic { + Atomic { + ptr: atomic::AtomicPtr::new(0 as *mut _), + _marker: PhantomData + } + } + + #[cfg(not(feature = "nightly"))] + pub fn null() -> Atomic { + Atomic { + ptr: atomic::AtomicPtr::new(0 as *mut _), + _marker: PhantomData + } + } + + /// Create a new atomic pointer + pub fn new(data: T) -> Atomic { + Atomic { + ptr: atomic::AtomicPtr::new(Box::into_raw(Box::new(data))), + _marker: PhantomData + } + } + + /// Do an atomic load with the given memory ordering. + /// + /// In order to perform the load, we must pass in a borrow of a + /// `Guard`. This is a way of guaranteeing that the thread has pinned the + /// epoch for the entire lifetime `'a`. In return, you get an optional + /// `Shared` pointer back (`None` if the `Atomic` is currently null), with + /// lifetime tied to the guard. + /// + /// # Panics + /// + /// Panics if `ord` is `Release` or `AcqRel`. + pub fn load<'a>(&self, ord: Ordering, _: &'a Guard) -> Option> { + unsafe { Shared::from_raw(self.ptr.load(ord)) } + } + + /// Do an atomic store with the given memory ordering. + /// + /// Transfers ownership of the given `Owned` pointer, if any. Since no + /// lifetime information is acquired, no `Guard` value is needed. + /// + /// # Panics + /// + /// Panics if `ord` is `Acquire` or `AcqRel`. + pub fn store(&self, val: Option>, ord: Ordering) { + self.ptr.store(opt_owned_into_raw(val), ord) + } + + /// Do an atomic store with the given memory ordering, immediately yielding + /// a shared reference to the pointer that was stored. + /// + /// Transfers ownership of the given `Owned` pointer, yielding a `Shared` + /// reference to it. Since the reference is valid only for the curent epoch, + /// it's lifetime is tied to a `Guard` value. + /// + /// # Panics + /// + /// Panics if `ord` is `Acquire` or `AcqRel`. + pub fn store_and_ref<'a>(&self, val: Owned, ord: Ordering, _: &'a Guard) + -> Shared<'a, T> + { + unsafe { + let shared = Shared::from_owned(val); + self.store_shared(Some(shared), ord); + shared + } + } + + /// Do an atomic store of a `Shared` pointer with the given memory ordering. + /// + /// This operation does not require a guard, because it does not yield any + /// new information about the lifetime of a pointer. + /// + /// # Panics + /// + /// Panics if `ord` is `Acquire` or `AcqRel`. + pub fn store_shared(&self, val: Option>, ord: Ordering) { + self.ptr.store(opt_shared_into_raw(val), ord) + } + + /// Do a compare-and-set from a `Shared` to an `Owned` pointer with the + /// given memory ordering. + /// + /// As with `store`, this operation does not require a guard; it produces no new + /// lifetime information. The `Result` indicates whether the CAS succeeded; if + /// not, ownership of the `new` pointer is returned to the caller. + pub fn cas(&self, old: Option>, new: Option>, ord: Ordering) + -> Result<(), Option>> + { + if self.ptr.compare_and_swap(opt_shared_into_raw(old), + opt_owned_as_raw(&new), + ord) == opt_shared_into_raw(old) + { + mem::forget(new); + Ok(()) + } else { + Err(new) + } + } + + /// Do a compare-and-set from a `Shared` to an `Owned` pointer with the + /// given memory ordering, immediatley acquiring a new `Shared` reference to + /// the previously-owned pointer if successful. + /// + /// This operation is analogous to `store_and_ref`. + pub fn cas_and_ref<'a>(&self, old: Option>, new: Owned, + ord: Ordering, _: &'a Guard) + -> Result, Owned> + { + if self.ptr.compare_and_swap(opt_shared_into_raw(old), new.as_raw(), ord) + == opt_shared_into_raw(old) + { + Ok(unsafe { Shared::from_owned(new) }) + } else { + Err(new) + } + } + + /// Do a compare-and-set from a `Shared` to another `Shared` pointer with + /// the given memory ordering. + /// + /// The boolean return value is `true` when the CAS is successful. + pub fn cas_shared(&self, old: Option>, new: Option>, ord: Ordering) + -> bool + { + self.ptr.compare_and_swap(opt_shared_into_raw(old), + opt_shared_into_raw(new), + ord) == opt_shared_into_raw(old) + } + + /// Do an atomic swap with an `Owned` pointer with the given memory ordering. + pub fn swap<'a>(&self, new: Option>, ord: Ordering, _: &'a Guard) + -> Option> { + unsafe { Shared::from_raw(self.ptr.swap(opt_owned_into_raw(new), ord)) } + } + + /// Do an atomic swap with a `Shared` pointer with the given memory ordering. + pub fn swap_shared<'a>(&self, new: Option>, ord: Ordering, _: &'a Guard) + -> Option> { + unsafe { Shared::from_raw(self.ptr.swap(opt_shared_into_raw(new), ord)) } + } +} diff --git a/crossbeam-0.3.2/src/epoch/garbage.rs b/crossbeam-0.3.2/src/epoch/garbage.rs new file mode 100644 index 000000000..9b66653ea --- /dev/null +++ b/crossbeam-0.3.2/src/epoch/garbage.rs @@ -0,0 +1,144 @@ +// Data structures for storing garbage to be freed later (once the +// epochs have sufficiently advanced). +// +// In general, we try to manage the garbage thread locally whenever +// possible. Each thread keep track of three bags of garbage. But if a +// thread is exiting, these bags must be moved into the global garbage +// bags. + +use std::ptr; +use std::mem; +use std::sync::atomic::AtomicPtr; +use std::sync::atomic::Ordering::{Relaxed, Release, Acquire}; + +use ZerosValid; + +/// One item of garbage. +/// +/// Stores enough information to do a deallocation. +#[derive(Debug)] +struct Item { + ptr: *mut u8, + free: unsafe fn(*mut u8), +} + +/// A single, thread-local bag of garbage. +#[derive(Debug)] +pub struct Bag(Vec); + +impl Bag { + fn new() -> Bag { + Bag(vec![]) + } + + fn insert(&mut self, elem: *mut T) { + let size = mem::size_of::(); + if size > 0 { + self.0.push(Item { + ptr: elem as *mut u8, + free: free::, + }) + } + unsafe fn free(t: *mut u8) { + drop(Vec::from_raw_parts(t as *mut T, 0, 1)); + } + } + + fn len(&self) -> usize { + self.0.len() + } + + /// Deallocate all garbage in the bag + pub unsafe fn collect(&mut self) { + let mut data = mem::replace(&mut self.0, Vec::new()); + for item in data.iter() { + (item.free)(item.ptr); + } + data.truncate(0); + self.0 = data; + } +} + +// needed because the bags store raw pointers. +unsafe impl Send for Bag {} +unsafe impl Sync for Bag {} + +/// A thread-local set of garbage bags. +#[derive(Debug)] +pub struct Local { + /// Garbage added at least one epoch behind the current local epoch + pub old: Bag, + /// Garbage added in the current local epoch or earlier + pub cur: Bag, + /// Garbage added in the current *global* epoch + pub new: Bag, +} + +impl Local { + pub fn new() -> Local { + Local { + old: Bag::new(), + cur: Bag::new(), + new: Bag::new(), + } + } + + pub fn insert(&mut self, elem: *mut T) { + self.new.insert(elem) + } + + /// Collect one epoch of garbage, rotating the local garbage bags. + pub unsafe fn collect(&mut self) { + let ret = self.old.collect(); + mem::swap(&mut self.old, &mut self.cur); + mem::swap(&mut self.cur, &mut self.new); + ret + } + + pub fn size(&self) -> usize { + self.old.len() + self.cur.len() + self.new.len() + } +} + +/// A concurrent garbage bag, currently based on Treiber's stack. +/// +/// The elements are themselves owned `Bag`s. +#[derive(Debug)] +pub struct ConcBag { + head: AtomicPtr, +} + +unsafe impl ZerosValid for ConcBag {} + +#[derive(Debug)] +struct Node { + data: Bag, + next: AtomicPtr, +} + +impl ConcBag { + pub fn insert(&self, t: Bag){ + let n = Box::into_raw(Box::new( + Node { data: t, next: AtomicPtr::new(ptr::null_mut()) })); + loop { + let head = self.head.load(Acquire); + unsafe { (*n).next.store(head, Relaxed) }; + if self.head.compare_and_swap(head, n, Release) == head { break } + } + } + + pub unsafe fn collect(&self) { + // check to avoid xchg instruction + // when no garbage exists + let mut head = self.head.load(Relaxed); + if head != ptr::null_mut() { + head = self.head.swap(ptr::null_mut(), Acquire); + + while head != ptr::null_mut() { + let mut n = Box::from_raw(head); + n.data.collect(); + head = n.next.load(Relaxed); + } + } + } +} diff --git a/crossbeam-0.3.2/src/epoch/global.rs b/crossbeam-0.3.2/src/epoch/global.rs new file mode 100644 index 000000000..21d993b6e --- /dev/null +++ b/crossbeam-0.3.2/src/epoch/global.rs @@ -0,0 +1,95 @@ +// Definition of global epoch state. The `get` function is the way to +// access this data externally (until const fn is stabilized...). + +use std::sync::atomic::AtomicUsize; + +use CachePadded; +use epoch::garbage; +use epoch::participants::Participants; + +/// Global epoch state +#[derive(Debug)] +pub struct EpochState { + /// Current global epoch + pub epoch: CachePadded, + + // FIXME: move this into the `garbage` module, rationalize API + /// Global garbage bags + pub garbage: [CachePadded; 3], + + /// Participant list + pub participants: Participants, +} + +unsafe impl Send for EpochState {} +unsafe impl Sync for EpochState {} + +pub use self::imp::get; + +#[cfg(not(feature = "nightly"))] +mod imp { + use std::mem; + use std::sync::atomic::{self, AtomicUsize}; + use std::sync::atomic::Ordering::Relaxed; + + use super::EpochState; + use CachePadded; + use epoch::participants::Participants; + + impl EpochState { + fn new() -> EpochState { + EpochState { + epoch: CachePadded::zeroed(), + garbage: [CachePadded::zeroed(), + CachePadded::zeroed(), + CachePadded::zeroed()], + participants: Participants::new(), + } + } + } + + static EPOCH: AtomicUsize = atomic::ATOMIC_USIZE_INIT; + + pub fn get() -> &'static EpochState { + let mut addr = EPOCH.load(Relaxed); + + if addr == 0 { + let boxed = Box::new(EpochState::new()); + let raw = Box::into_raw(boxed); + + addr = EPOCH.compare_and_swap(0, raw as usize, Relaxed); + if addr != 0 { + let boxed = unsafe { Box::from_raw(raw) }; + mem::drop(boxed); + } else { + addr = raw as usize; + } + } + + unsafe { + &*(addr as *mut EpochState) + } + } +} + +#[cfg(feature = "nightly")] +mod imp { + use super::EpochState; + use CachePadded; + use epoch::participants::Participants; + + impl EpochState { + const fn new() -> EpochState { + EpochState { + epoch: CachePadded::zeroed(), + garbage: [CachePadded::zeroed(), + CachePadded::zeroed(), + CachePadded::zeroed()], + participants: Participants::new(), + } + } + } + + static EPOCH: EpochState = EpochState::new(); + pub fn get() -> &'static EpochState { &EPOCH } +} diff --git a/crossbeam-0.3.2/src/epoch/guard.rs b/crossbeam-0.3.2/src/epoch/guard.rs new file mode 100644 index 000000000..4347cdff1 --- /dev/null +++ b/crossbeam-0.3.2/src/epoch/guard.rs @@ -0,0 +1,56 @@ +use std::marker; + +use super::{local, Shared}; + +/// An RAII-style guard for pinning the current epoch. +/// +/// A guard must be acquired before most operations on an `Atomic` pointer. On +/// destruction, it unpins the epoch. +#[must_use] +#[derive(Debug)] +pub struct Guard { + _marker: marker::PhantomData<*mut ()>, // !Send and !Sync +} + +/// Pin the current epoch. +/// +/// Threads generally pin before interacting with a lock-free data +/// structure. Pinning requires a full memory barrier, so is somewhat +/// expensive. It is rentrant -- you can safely acquire nested guards, and only +/// the first guard requires a barrier. Thus, in cases where you expect to +/// perform several lock-free operations in quick succession, you may consider +/// pinning around the entire set of operations. +pub fn pin() -> Guard { + local::with_participant(|p| { + let entered = p.enter(); + + let g = Guard { + _marker: marker::PhantomData, + }; + + if entered && p.should_gc() { + p.try_collect(&g); + } + + g + }) +} + +impl Guard { + /// Assert that the value is no longer reachable from a lock-free data + /// structure and should be collected when sufficient epochs have passed. + pub unsafe fn unlinked(&self, val: Shared) { + local::with_participant(|p| p.reclaim(val.as_raw())) + } + + /// Move the thread-local garbage into the global set of garbage. + pub fn migrate_garbage(&self) { + local::with_participant(|p| p.migrate_garbage()) + } +} + +impl Drop for Guard { + fn drop(&mut self) { + local::with_participant(|p| p.exit()); + } +} diff --git a/crossbeam-0.3.2/src/epoch/local.rs b/crossbeam-0.3.2/src/epoch/local.rs new file mode 100644 index 000000000..98fdb6013 --- /dev/null +++ b/crossbeam-0.3.2/src/epoch/local.rs @@ -0,0 +1,38 @@ +// Manage the thread-local state, providing access to a `Participant` record. + +use std::sync::atomic::Ordering::Relaxed; + +use epoch::participant::Participant; +use epoch::global; + +#[derive(Debug)] +struct LocalEpoch { + participant: *const Participant, +} + +impl LocalEpoch { + fn new() -> LocalEpoch { + LocalEpoch { participant: global::get().participants.enroll() } + } + + fn get(&self) -> &Participant { + unsafe { &*self.participant } + } +} + +// FIXME: avoid leaking when all threads have exited +impl Drop for LocalEpoch { + fn drop(&mut self) { + let p = self.get(); + p.enter(); + p.migrate_garbage(); + p.exit(); + p.active.store(false, Relaxed); + } +} + +thread_local!(static LOCAL_EPOCH: LocalEpoch = LocalEpoch::new() ); + +pub fn with_participant(f: F) -> T where F: FnOnce(&Participant) -> T { + LOCAL_EPOCH.with(|e| f(e.get())) +} diff --git a/crossbeam-0.3.2/src/epoch/mod.rs b/crossbeam-0.3.2/src/epoch/mod.rs new file mode 100644 index 000000000..17615fc15 --- /dev/null +++ b/crossbeam-0.3.2/src/epoch/mod.rs @@ -0,0 +1,265 @@ +//! Epoch-based memory management +//! +//! This module provides fast, easy to use memory management for lock free data +//! structures. It's inspired by [Keir Fraser's *epoch-based +//! reclamation*](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf). +//! +//! The basic problem this is solving is the fact that when one thread has +//! removed a node from a data structure, other threads may still have pointers +//! to that node (in the form of snapshots that will be validated through things +//! like compare-and-swap), so the memory cannot be immediately freed. Put differently: +//! +//! 1. There are two sources of reachability at play -- the data structure, and +//! the snapshots in threads accessing it. Before we delete a node, we need to know +//! that it cannot be reached in either of these ways. +//! +//! 2. Once a node has been unlinked from the data structure, no *new* snapshots +//! reaching it will be created. +//! +//! Using the epoch scheme is fairly straightforward, and does not require +//! understanding any of the implementation details: +//! +//! - When operating on a shared data structure, a thread must "pin the current +//! epoch", which is done by calling `pin()`. This function returns a `Guard` +//! which unpins the epoch when destroyed. +//! +//! - When the thread subsequently reads from a lock-free data structure, the +//! pointers it extracts act like references with lifetime tied to the +//! `Guard`. This allows threads to safely read from snapshotted data, being +//! guaranteed that the data will remain allocated until they exit the epoch. +//! +//! To put the `Guard` to use, Crossbeam provides a set of three pointer types meant to work together: +//! +//! - `Owned`, akin to `Box`, which points to uniquely-owned data that has +//! not yet been published in a concurrent data structure. +//! +//! - `Shared<'a, T>`, akin to `&'a T`, which points to shared data that may or may +//! not be reachable from a data structure, but it guaranteed not to be freed +//! during lifetime `'a`. +//! +//! - `Atomic`, akin to `std::sync::atomic::AtomicPtr`, which provides atomic +//! updates to a pointer using the `Owned` and `Shared` types, and connects them +//! to a `Guard`. +//! +//! Each of these types provides further documentation on usage. +//! +//! # Example +//! +//! ``` +//! use std::sync::atomic::Ordering::{Acquire, Release, Relaxed}; +//! use std::ptr; +//! +//! use crossbeam::epoch::{self, Atomic, Owned}; +//! +//! struct TreiberStack { +//! head: Atomic>, +//! } +//! +//! struct Node { +//! data: T, +//! next: Atomic>, +//! } +//! +//! impl TreiberStack { +//! fn new() -> TreiberStack { +//! TreiberStack { +//! head: Atomic::null() +//! } +//! } +//! +//! fn push(&self, t: T) { +//! // allocate the node via Owned +//! let mut n = Owned::new(Node { +//! data: t, +//! next: Atomic::null(), +//! }); +//! +//! // become active +//! let guard = epoch::pin(); +//! +//! loop { +//! // snapshot current head +//! let head = self.head.load(Relaxed, &guard); +//! +//! // update `next` pointer with snapshot +//! n.next.store_shared(head, Relaxed); +//! +//! // if snapshot is still good, link in the new node +//! match self.head.cas_and_ref(head, n, Release, &guard) { +//! Ok(_) => return, +//! Err(owned) => n = owned, +//! } +//! } +//! } +//! +//! fn pop(&self) -> Option { +//! // become active +//! let guard = epoch::pin(); +//! +//! loop { +//! // take a snapshot +//! match self.head.load(Acquire, &guard) { +//! // the stack is non-empty +//! Some(head) => { +//! // read through the snapshot, *safely*! +//! let next = head.next.load(Relaxed, &guard); +//! +//! // if snapshot is still good, update from `head` to `next` +//! if self.head.cas_shared(Some(head), next, Release) { +//! unsafe { +//! // mark the node as unlinked +//! guard.unlinked(head); +//! +//! // extract out the data from the now-unlinked node +//! return Some(ptr::read(&(*head).data)) +//! } +//! } +//! } +//! +//! // we observed the stack empty +//! None => return None +//! } +//! } +//! } +//! } +//! ``` + +// FIXME: document implementation details + +mod atomic; +mod garbage; +mod global; +mod guard; +mod local; +mod participant; +mod participants; + +pub use self::atomic::Atomic; +pub use self::guard::{pin, Guard}; + +use std::ops::{Deref, DerefMut}; +use std::ptr; +use std::mem; + +/// Like `Box`: an owned, heap-allocated data value of type `T`. +#[derive(Debug)] +pub struct Owned { + data: Box, +} + +impl Owned { + /// Move `t` to a new heap allocation. + pub fn new(t: T) -> Owned { + Owned { data: Box::new(t) } + } + + fn as_raw(&self) -> *mut T { + self.deref() as *const _ as *mut _ + } + + /// Move data out of the owned box, deallocating the box. + pub fn into_inner(self) -> T { + *self.data + } +} + +impl Deref for Owned { + type Target = T; + fn deref(&self) -> &T { + &self.data + } +} + +impl DerefMut for Owned { + fn deref_mut(&mut self) -> &mut T { + &mut self.data + } +} + +#[derive(PartialEq, Eq)] +/// Like `&'a T`: a shared reference valid for lifetime `'a`. +#[derive(Debug)] +pub struct Shared<'a, T: 'a> { + data: &'a T, +} + +impl<'a, T> Copy for Shared<'a, T> {} +impl<'a, T> Clone for Shared<'a, T> { + fn clone(&self) -> Shared<'a, T> { + Shared { data: self.data } + } +} + +impl<'a, T> Deref for Shared<'a, T> { + type Target = &'a T; + fn deref(&self) -> &&'a T { + &self.data + } +} + +impl<'a, T> Shared<'a, T> { + unsafe fn from_raw(raw: *mut T) -> Option> { + if raw == ptr::null_mut() { None } + else { + Some(Shared { + data: mem::transmute::<*mut T, &T>(raw) + }) + } + } + + unsafe fn from_ref(r: &T) -> Shared<'a, T> { + Shared { data: mem::transmute(r) } + } + + unsafe fn from_owned(owned: Owned) -> Shared<'a, T> { + let ret = Shared::from_ref(owned.deref()); + mem::forget(owned); + ret + } + + pub fn as_raw(&self) -> *mut T { + self.data as *const _ as *mut _ + } +} + + +#[cfg(test)] +mod test { + use std::sync::atomic::Ordering; + use super::*; + use epoch; + + #[test] + fn test_no_drop() { + static mut DROPS: i32 = 0; + struct Test; + impl Drop for Test { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + } + } + let g = pin(); + + let x = Atomic::null(); + x.store(Some(Owned::new(Test)), Ordering::Relaxed); + x.store_and_ref(Owned::new(Test), Ordering::Relaxed, &g); + let y = x.load(Ordering::Relaxed, &g); + let z = x.cas_and_ref(y, Owned::new(Test), Ordering::Relaxed, &g).ok(); + let _ = x.cas(z, Some(Owned::new(Test)), Ordering::Relaxed); + x.swap(Some(Owned::new(Test)), Ordering::Relaxed, &g); + + unsafe { + assert_eq!(DROPS, 0); + } + } + + #[test] + fn test_new() { + let guard = epoch::pin(); + let my_atomic = Atomic::new(42); + + assert_eq!(**my_atomic.load(Ordering::Relaxed, &guard).unwrap(), 42); + } +} diff --git a/crossbeam-0.3.2/src/epoch/participant.rs b/crossbeam-0.3.2/src/epoch/participant.rs new file mode 100644 index 000000000..2ec07775b --- /dev/null +++ b/crossbeam-0.3.2/src/epoch/participant.rs @@ -0,0 +1,133 @@ +// Manages a single participant in the epoch scheme. This is where all +// of the actual epoch management logic happens! + +use std::mem; +use std::cell::UnsafeCell; +use std::fmt; +use std::sync::atomic::{self, AtomicUsize, AtomicBool}; +use std::sync::atomic::Ordering::{Relaxed, Acquire, Release, SeqCst}; + +use epoch::{Atomic, Guard, garbage, global}; +use epoch::participants::ParticipantNode; + +/// Thread-local data for epoch participation. +pub struct Participant { + /// The local epoch. + epoch: AtomicUsize, + + /// Number of pending uses of `epoch::pin()`; keeping a count allows for + /// reentrant use of epoch management. + in_critical: AtomicUsize, + + /// Thread-local garbage tracking + garbage: UnsafeCell, + + /// Is the thread still active? Becomes `false` when the thread exits. This + /// is ultimately used to free `Participant` records. + pub active: AtomicBool, + + /// The participant list is coded intrusively; here's the `next` pointer. + pub next: Atomic, +} + +impl fmt::Debug for Participant { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Participant {{ ... }}") + } +} + +unsafe impl Sync for Participant {} + +const GC_THRESH: usize = 32; + +impl Participant { + pub fn new() -> Participant { + Participant { + epoch: AtomicUsize::new(0), + in_critical: AtomicUsize::new(0), + active: AtomicBool::new(true), + garbage: UnsafeCell::new(garbage::Local::new()), + next: Atomic::null(), + } + } + + /// Enter a critical section. + /// + /// This method is reentrant, allowing for nested critical sections. + /// + /// Returns `true` is this is the first entry on the stack (as opposed to a + /// re-entrant call). + pub fn enter(&self) -> bool { + let new_count = self.in_critical.load(Relaxed) + 1; + self.in_critical.store(new_count, Relaxed); + if new_count > 1 { return false } + + atomic::fence(SeqCst); + + let global_epoch = global::get().epoch.load(Relaxed); + if global_epoch != self.epoch.load(Relaxed) { + self.epoch.store(global_epoch, Relaxed); + unsafe { (*self.garbage.get()).collect(); } + } + + true + } + + /// Exit the current (nested) critical section. + pub fn exit(&self) { + let new_count = self.in_critical.load(Relaxed) - 1; + self.in_critical.store( + new_count, + if new_count > 0 { Relaxed } else { Release }); + } + + /// Begin the reclamation process for a piece of data. + pub unsafe fn reclaim(&self, data: *mut T) { + (*self.garbage.get()).insert(data); + } + + /// Attempt to collect garbage by moving the global epoch forward. + /// + /// Returns `true` on success. + pub fn try_collect(&self, guard: &Guard) -> bool { + let cur_epoch = global::get().epoch.load(SeqCst); + + for p in global::get().participants.iter(guard) { + if p.in_critical.load(Relaxed) > 0 && p.epoch.load(Relaxed) != cur_epoch { + return false + } + } + + let new_epoch = cur_epoch.wrapping_add(1); + atomic::fence(Acquire); + if global::get().epoch.compare_and_swap(cur_epoch, new_epoch, SeqCst) != cur_epoch { + return false + } + + unsafe { + (*self.garbage.get()).collect(); + global::get().garbage[new_epoch.wrapping_add(1) % 3].collect(); + } + self.epoch.store(new_epoch, Release); + + true + } + + /// Move the current thread-local garbage into the global garbage bags. + pub fn migrate_garbage(&self) { + let cur_epoch = self.epoch.load(Relaxed); + let local = unsafe { mem::replace(&mut *self.garbage.get(), garbage::Local::new()) }; + global::get().garbage[cur_epoch.wrapping_sub(1) % 3].insert(local.old); + global::get().garbage[cur_epoch % 3].insert(local.cur); + global::get().garbage[global::get().epoch.load(Relaxed) % 3].insert(local.new); + } + + /// How much garbage is this participant currently storing? + pub fn garbage_size(&self) -> usize { + unsafe { (*self.garbage.get()).size() } + } + /// Is this participant past its local GC threshhold? + pub fn should_gc(&self) -> bool { + self.garbage_size() >= GC_THRESH + } +} diff --git a/crossbeam-0.3.2/src/epoch/participants.rs b/crossbeam-0.3.2/src/epoch/participants.rs new file mode 100644 index 000000000..7bd79f378 --- /dev/null +++ b/crossbeam-0.3.2/src/epoch/participants.rs @@ -0,0 +1,120 @@ +// Manages the global participant list, which is an intrustive list in +// which items are lazily removed on traversal (after being +// "logically" deleted by becoming inactive.) + +use std::mem; +use std::ops::{Deref, DerefMut}; +use std::sync::atomic::Ordering::{Relaxed, Acquire, Release}; + +use epoch::{Atomic, Owned, Guard}; +use epoch::participant::Participant; +use CachePadded; + +/// Global, threadsafe list of threads participating in epoch management. +#[derive(Debug)] +pub struct Participants { + head: Atomic +} + +#[derive(Debug)] +pub struct ParticipantNode(CachePadded); + +impl ParticipantNode { + pub fn new() -> ParticipantNode { + ParticipantNode(CachePadded::new(Participant::new())) + } +} + +impl Deref for ParticipantNode { + type Target = Participant; + fn deref(&self) -> &Participant { + &self.0 + } +} + +impl DerefMut for ParticipantNode { + fn deref_mut(&mut self) -> &mut Participant { + &mut self.0 + } +} + +impl Participants { + #[cfg(not(feature = "nightly"))] + pub fn new() -> Participants { + Participants { head: Atomic::null() } + } + + #[cfg(feature = "nightly")] + pub const fn new() -> Participants { + Participants { head: Atomic::null() } + } + + /// Enroll a new thread in epoch management by adding a new `Particpant` + /// record to the global list. + pub fn enroll(&self) -> *const Participant { + let mut participant = Owned::new(ParticipantNode::new()); + + // we ultimately use epoch tracking to free Participant nodes, but we + // can't actually enter an epoch here, so fake it; we know the node + // can't be removed until marked inactive anyway. + let fake_guard = (); + let g: &'static Guard = unsafe { mem::transmute(&fake_guard) }; + loop { + let head = self.head.load(Relaxed, g); + participant.next.store_shared(head, Relaxed); + match self.head.cas_and_ref(head, participant, Release, g) { + Ok(shared) => { + let shared: &Participant = &shared; + return shared; + } + Err(owned) => { + participant = owned; + } + } + } + } + + pub fn iter<'a>(&'a self, g: &'a Guard) -> Iter<'a> { + Iter { + guard: g, + next: &self.head, + needs_acq: true, + } + } +} + +#[derive(Debug)] +pub struct Iter<'a> { + // pin to an epoch so that we can free inactive nodes + guard: &'a Guard, + next: &'a Atomic, + + // an Acquire read is needed only for the first read, due to release + // sequences + needs_acq: bool, +} + +impl<'a> Iterator for Iter<'a> { + type Item = &'a Participant; + fn next(&mut self) -> Option<&'a Participant> { + let mut cur = if self.needs_acq { + self.needs_acq = false; + self.next.load(Acquire, self.guard) + } else { + self.next.load(Relaxed, self.guard) + }; + + while let Some(n) = cur { + // attempt to clean up inactive nodes + if !n.active.load(Relaxed) { + cur = n.next.load(Relaxed, self.guard); + // TODO: actually reclaim inactive participants! + } else { + self.next = &n.next; + return Some(&n) + } + } + + None + } +} diff --git a/crossbeam-0.3.2/src/lib.rs b/crossbeam-0.3.2/src/lib.rs new file mode 100644 index 000000000..fbaee22dd --- /dev/null +++ b/crossbeam-0.3.2/src/lib.rs @@ -0,0 +1,68 @@ +//! Support for concurrent and parallel programming. +//! +//! This crate is an early work in progress. The focus for the moment is +//! concurrency: +//! +//! - **Non-blocking data structures**. These data structures allow for high +//! performance, highly-concurrent access, much superior to wrapping with a +//! `Mutex`. Ultimately the goal is to include stacks, queues, deques, bags, +//! sets and maps. These live in the `sync` module. +//! +//! - **Memory management**. Because non-blocking data structures avoid global +//! synchronization, it is not easy to tell when internal data can be safely +//! freed. The `mem` module provides generic, easy to use, and high-performance +//! APIs for managing memory in these cases. These live in the `mem` module. +//! +//! - **Synchronization**. The standard library provides a few synchronization +//! primitives (locks, barriers, etc) but this crate seeks to expand that set +//! to include more advanced/niche primitives, as well as userspace +//! alternatives. These live in the `sync` module. +//! +//! - **Scoped thread API**. Finally, the crate provides a "scoped" thread API, +//! making it possible to spawn threads that share stack data with their +//! parents. This functionality is exported at the top-level. + +//#![deny(missing_docs)] + +#![cfg_attr(feature = "nightly", + feature(const_fn, repr_simd, optin_builtin_traits))] + +use std::thread; +use std::io; + +pub use scoped::{scope, Scope, ScopedJoinHandle}; + +pub mod epoch; +pub mod sync; +mod scoped; + +mod cache_padded; +pub use self::cache_padded::{CachePadded, ZerosValid}; + +#[doc(hidden)] +trait FnBox { + fn call_box(self: Box); +} + +impl FnBox for F { + fn call_box(self: Box) { (*self)() } +} + +/// Like `std::thread::spawn`, but without the closure bounds. +pub unsafe fn spawn_unsafe<'a, F>(f: F) -> thread::JoinHandle<()> where F: FnOnce() + Send + 'a { + let builder = thread::Builder::new(); + builder_spawn_unsafe(builder, f).unwrap() +} + +/// Like `std::thread::Builder::spawn`, but without the closure bounds. +pub unsafe fn builder_spawn_unsafe<'a, F>(builder: thread::Builder, f: F) + -> io::Result> + where F: FnOnce() + Send + 'a +{ + use std::mem; + + let closure: Box = Box::new(f); + let closure: Box = mem::transmute(closure); + builder.spawn(move || closure.call_box()) +} + diff --git a/crossbeam-0.3.2/src/scoped.rs b/crossbeam-0.3.2/src/scoped.rs new file mode 100644 index 000000000..81ea85fa3 --- /dev/null +++ b/crossbeam-0.3.2/src/scoped.rs @@ -0,0 +1,314 @@ +use std::cell::RefCell; +use std::fmt; +use std::mem; +use std::rc::Rc; +use std::sync::atomic::Ordering; +use std::sync::Arc; +use std::thread; +use std::io; + +use {builder_spawn_unsafe, FnBox}; +use sync::AtomicOption; + +pub struct Scope<'a> { + dtors: RefCell>> +} + +struct DtorChain<'a> { + dtor: Box, + next: Option>> +} + +enum JoinState { + Running(thread::JoinHandle<()>), + Joined, +} + +impl JoinState { + fn join(&mut self) { + let mut state = JoinState::Joined; + mem::swap(self, &mut state); + if let JoinState::Running(handle) = state { + let res = handle.join(); + + if !thread::panicking() { res.unwrap(); } + } + } +} + +/// A handle to a scoped thread +pub struct ScopedJoinHandle { + inner: Rc>, + packet: Arc>, + thread: thread::Thread, +} + +/// Create a new `scope`, for deferred destructors. +/// +/// Scopes, in particular, support [*scoped thread spawning*](struct.Scope.html#method.spawn). +/// +/// # Examples +/// +/// Creating and using a scope: +/// +/// ``` +/// crossbeam::scope(|scope| { +/// scope.defer(|| println!("Exiting scope")); +/// scope.spawn(|| println!("Running child thread in scope")) +/// }); +/// // Prints messages in the reverse order written +/// ``` +pub fn scope<'a, F, R>(f: F) -> R where F: FnOnce(&Scope<'a>) -> R { + let mut scope = Scope { dtors: RefCell::new(None) }; + let ret = f(&scope); + scope.drop_all(); + ret +} + +impl<'a> fmt::Debug for Scope<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Scope {{ ... }}") + } +} + +impl fmt::Debug for ScopedJoinHandle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ScopedJoinHandle {{ ... }}") + } +} + +impl<'a> Scope<'a> { + // This method is carefully written in a transactional style, so + // that it can be called directly and, if any dtor panics, can be + // resumed in the unwinding this causes. By initially running the + // method outside of any destructor, we avoid any leakage problems + // due to @rust-lang/rust#14875. + fn drop_all(&mut self) { + loop { + // use a separate scope to ensure that the RefCell borrow + // is relinquished before running `dtor` + let dtor = { + let mut dtors = self.dtors.borrow_mut(); + if let Some(mut node) = dtors.take() { + *dtors = node.next.take().map(|b| *b); + node.dtor + } else { + return + } + }; + dtor.call_box() + } + } + + /// Schedule code to be executed when exiting the scope. + /// + /// This is akin to having a destructor on the stack, except that it is + /// *guaranteed* to be run. + pub fn defer(&self, f: F) where F: FnOnce() + 'a { + let mut dtors = self.dtors.borrow_mut(); + *dtors = Some(DtorChain { + dtor: Box::new(f), + next: dtors.take().map(Box::new) + }); + } + + /// Create a scoped thread. + /// + /// `spawn` is similar to the [`spawn`][spawn] function in Rust's standard library. The + /// difference is that this thread is scoped, meaning that it's guaranteed to terminate + /// before the current stack frame goes away, allowing you to reference the parent stack frame + /// directly. This is ensured by having the parent thread join on the child thread before the + /// scope exits. + /// + /// [spawn]: http://doc.rust-lang.org/std/thread/fn.spawn.html + /// + /// # Examples + /// + /// A basic scoped thread: + /// + /// ``` + /// crossbeam::scope(|scope| { + /// scope.spawn(|| { + /// println!("Hello from a scoped thread!"); + /// }); + /// }); + /// ``` + /// + /// When writing concurrent Rust programs, you'll sometimes see a pattern like this, using + /// [`std::thread::spawn`][spawn]: + /// + /// ```ignore + /// let array = [1, 2, 3]; + /// let mut guards = vec![]; + /// + /// for i in &array { + /// let guard = std::thread::spawn(move || { + /// println!("element: {}", i); + /// }); + /// + /// guards.push(guard); + /// } + /// + /// for guard in guards { + /// guard.join().unwrap(); + /// } + /// ``` + /// + /// The basic pattern is: + /// + /// 1. Iterate over some collection. + /// 2. Spin up a thread to operate on each part of the collection. + /// 3. Join all the threads. + /// + /// However, this code actually gives an error: + /// + /// ```text + /// error: `array` does not live long enough + /// for i in &array { + /// ^~~~~ + /// in expansion of for loop expansion + /// note: expansion site + /// note: reference must be valid for the static lifetime... + /// note: ...but borrowed value is only valid for the block suffix following statement 0 at ... + /// let array = [1, 2, 3]; + /// let mut guards = vec![]; + /// + /// for i in &array { + /// let guard = std::thread::spawn(move || { + /// println!("element: {}", i); + /// ... + /// error: aborting due to previous error + /// ``` + /// + /// Because [`std::thread::spawn`][spawn] doesn't know about this scope, it requires a + /// `'static` lifetime. One way of giving it a proper lifetime is to use an [`Arc`][arc]: + /// + /// [arc]: http://doc.rust-lang.org/stable/std/sync/struct.Arc.html + /// + /// ``` + /// use std::sync::Arc; + /// + /// let array = Arc::new([1, 2, 3]); + /// let mut guards = vec![]; + /// + /// for i in 0..array.len() { + /// let a = array.clone(); + /// + /// let guard = std::thread::spawn(move || { + /// println!("element: {}", a[i]); + /// }); + /// + /// guards.push(guard); + /// } + /// + /// for guard in guards { + /// guard.join().unwrap(); + /// } + /// ``` + /// + /// But this introduces unnecessary allocation, as `Arc` puts its data on the heap, and we + /// also end up dealing with reference counts. We know that we're joining the threads before + /// our function returns, so just taking a reference _should_ be safe. Rust can't know that, + /// though. + /// + /// Enter scoped threads. Here's our original example, using `spawn` from crossbeam rather + /// than from `std::thread`: + /// + /// ``` + /// let array = [1, 2, 3]; + /// + /// crossbeam::scope(|scope| { + /// for i in &array { + /// scope.spawn(move || { + /// println!("element: {}", i); + /// }); + /// } + /// }); + /// ``` + /// + /// Much more straightforward. + pub fn spawn(&self, f: F) -> ScopedJoinHandle where + F: FnOnce() -> T + Send + 'a, T: Send + 'a + { + self.builder().spawn(f).unwrap() + } + + /// Generates the base configuration for spawning a scoped thread, from which configuration + /// methods can be chained. + pub fn builder<'s>(&'s self) -> ScopedThreadBuilder<'s, 'a> { + ScopedThreadBuilder { + scope: self, + builder: thread::Builder::new(), + } + } +} + +/// Scoped thread configuration. Provides detailed control over the properties and behavior of new +/// scoped threads. +pub struct ScopedThreadBuilder<'s, 'a: 's> { + scope: &'s Scope<'a>, + builder: thread::Builder, +} + +impl<'s, 'a: 's> ScopedThreadBuilder<'s, 'a> { + /// Names the thread-to-be. Currently the name is used for identification only in panic + /// messages. + pub fn name(mut self, name: String) -> ScopedThreadBuilder<'s, 'a> { + self.builder = self.builder.name(name); + self + } + + /// Sets the size of the stack for the new thread. + pub fn stack_size(mut self, size: usize) -> ScopedThreadBuilder<'s, 'a> { + self.builder = self.builder.stack_size(size); + self + } + + /// Spawns a new thread, and returns a join handle for it. + pub fn spawn(self, f: F) -> io::Result> + where F: FnOnce() -> T + Send + 'a, T: Send + 'a + { + let their_packet = Arc::new(AtomicOption::new()); + let my_packet = their_packet.clone(); + + let join_handle = try!(unsafe { + builder_spawn_unsafe(self.builder, move || { + their_packet.swap(f(), Ordering::Relaxed); + }) + }); + + let thread = join_handle.thread().clone(); + let deferred_handle = Rc::new(RefCell::new(JoinState::Running(join_handle))); + let my_handle = deferred_handle.clone(); + + self.scope.defer(move || { + let mut state = deferred_handle.borrow_mut(); + state.join(); + }); + + Ok(ScopedJoinHandle { + inner: my_handle, + packet: my_packet, + thread: thread, + }) + } +} + +impl ScopedJoinHandle { + /// Join the scoped thread, returning the result it produced. + pub fn join(self) -> T { + self.inner.borrow_mut().join(); + self.packet.take(Ordering::Relaxed).unwrap() + } + + /// Get the underlying thread handle. + pub fn thread(&self) -> &thread::Thread { + &self.thread + } +} + +impl<'a> Drop for Scope<'a> { + fn drop(&mut self) { + self.drop_all() + } +} diff --git a/crossbeam-0.3.2/src/sync/arc_cell.rs b/crossbeam-0.3.2/src/sync/arc_cell.rs new file mode 100644 index 000000000..e26d45a94 --- /dev/null +++ b/crossbeam-0.3.2/src/sync/arc_cell.rs @@ -0,0 +1,90 @@ +use std::marker::PhantomData; +use std::mem; +use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering}; + +/// A type providing atomic storage and retrieval of an `Arc`. +#[derive(Debug)] +pub struct ArcCell(AtomicUsize, PhantomData>); + +impl Drop for ArcCell { + fn drop(&mut self) { + self.take(); + } +} + +impl ArcCell { + /// Creates a new `ArcCell`. + pub fn new(t: Arc) -> ArcCell { + ArcCell(AtomicUsize::new(unsafe { mem::transmute(t) }), PhantomData) + } + + fn take(&self) -> Arc { + loop { + match self.0.swap(0, Ordering::Acquire) { + 0 => {} + n => return unsafe { mem::transmute(n) } + } + } + } + + fn put(&self, t: Arc) { + debug_assert_eq!(self.0.load(Ordering::SeqCst), 0); + self.0.store(unsafe { mem::transmute(t) }, Ordering::Release); + } + + /// Stores a new value in the `ArcCell`, returning the previous + /// value. + pub fn set(&self, t: Arc) -> Arc { + let old = self.take(); + self.put(t); + old + } + + /// Returns a copy of the value stored by the `ArcCell`. + pub fn get(&self) -> Arc { + let t = self.take(); + // NB: correctness here depends on Arc's clone impl not panicking + let out = t.clone(); + self.put(t); + out + } +} + +#[cfg(test)] +mod test { + use std::sync::Arc; + use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering}; + + use super::*; + + #[test] + fn basic() { + let r = ArcCell::new(Arc::new(0)); + assert_eq!(*r.get(), 0); + assert_eq!(*r.set(Arc::new(1)), 0); + assert_eq!(*r.get(), 1); + } + + #[test] + fn drop_runs() { + static DROPS: AtomicUsize = ATOMIC_USIZE_INIT; + + struct Foo; + + impl Drop for Foo { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let r = ArcCell::new(Arc::new(Foo)); + let _f = r.get(); + r.get(); + r.set(Arc::new(Foo)); + drop(_f); + assert_eq!(DROPS.load(Ordering::SeqCst), 1); + drop(r); + assert_eq!(DROPS.load(Ordering::SeqCst), 2); + } +} diff --git a/crossbeam-0.3.2/src/sync/atomic_option.rs b/crossbeam-0.3.2/src/sync/atomic_option.rs new file mode 100644 index 000000000..eca79861b --- /dev/null +++ b/crossbeam-0.3.2/src/sync/atomic_option.rs @@ -0,0 +1,49 @@ +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::ptr; + +unsafe impl Send for AtomicOption {} +unsafe impl Sync for AtomicOption {} + +#[derive(Debug)] +pub struct AtomicOption { + inner: AtomicPtr, +} + +impl Drop for AtomicOption { + fn drop(&mut self) { + let inner = self.inner.load(Ordering::Relaxed); + if !inner.is_null() { + unsafe { + drop(Box::from_raw(inner)); + } + } + } +} + +impl AtomicOption { + pub fn new() -> AtomicOption { + AtomicOption { inner: AtomicPtr::new(ptr::null_mut()) } + } + + fn swap_inner(&self, ptr: *mut T, order: Ordering) -> Option> { + let old = self.inner.swap(ptr, order); + if old.is_null() { + None + } else { + Some(unsafe { Box::from_raw(old) }) + } + } + + // allows re-use of allocation + pub fn swap_box(&self, t: Box, order: Ordering) -> Option> { + self.swap_inner(Box::into_raw(t), order) + } + + pub fn swap(&self, t: T, order: Ordering) -> Option { + self.swap_box(Box::new(t), order).map(|old| *old) + } + + pub fn take(&self, order: Ordering) -> Option { + self.swap_inner(ptr::null_mut(), order).map(|old| *old) + } +} diff --git a/crossbeam-0.3.2/src/sync/chase_lev.rs b/crossbeam-0.3.2/src/sync/chase_lev.rs new file mode 100644 index 000000000..7f6aa0915 --- /dev/null +++ b/crossbeam-0.3.2/src/sync/chase_lev.rs @@ -0,0 +1,605 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A lock-free concurrent work-stealing deque +//! +//! This module contains a hybrid implementation of the Chase-Lev work stealing deque +//! described in ["Dynamic Circular Work-Stealing Deque"][chase_lev] and the improved version +//! described in ["Correct and Efficient Work-Stealing for Weak Memory Models"][weak_chase_lev]. +//! The implementation is heavily based on the pseudocode found in the papers. +//! +//! # Example +//! +//! ``` +//! use crossbeam::sync::chase_lev; +//! let (worker, stealer) = chase_lev::deque(); +//! +//! // Only the worker may push/try_pop +//! worker.push(1); +//! worker.try_pop(); +//! +//! // Stealers take data from the other end of the deque +//! worker.push(1); +//! stealer.steal(); +//! +//! // Stealers can be cloned to have many stealers stealing in parallel +//! worker.push(1); +//! let stealer2 = stealer.clone(); +//! stealer2.steal(); +//! ``` +//! +//! [chase_lev]: http://neteril.org/~jeremie/Dynamic_Circular_Work_Queue.pdf +//! [weak_chase_lev]: http://www.di.ens.fr/~zappa/readings/ppopp13.pdf + +use std::cell::UnsafeCell; +use std::fmt; +use std::mem; +use std::ptr; +use std::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; +use std::sync::atomic::{AtomicIsize, fence}; +use std::sync::Arc; +use std::marker::PhantomData; +use std::cell::Cell; + +use epoch::{self, Atomic, Shared, Owned}; + +// Once the queue is less than 1/K full, then it will be downsized. Note that +// the deque requires that this number be less than 2. +const K: isize = 4; + +// Minimum number of bits that a buffer size should be. No buffer will resize to +// under this value, and all deques will initially contain a buffer of this +// size. +// +// The size in question is 1 << MIN_BITS +const MIN_BITS: u32 = 7; + +#[derive(Debug)] +struct Deque { + bottom: AtomicIsize, + top: AtomicIsize, + array: Atomic>, +} + +// FIXME: can these constraints be relaxed? +unsafe impl Send for Deque {} +unsafe impl Sync for Deque {} + +/// Worker half of the work-stealing deque. This worker has exclusive access to +/// one side of the deque, and uses `push` and `try_pop` method to manipulate it. +/// +/// There may only be one worker per deque, so `Worker` does not implement +/// `Clone` or `Copy`. +#[derive(Debug)] +pub struct Worker { + deque: Arc>, + + // Marker so that the Worker is Send but not Sync. The worker can only be + // accessed from a single thread at once. Ideally we would use a negative + // impl here but these are not stable yet. + marker: PhantomData>, +} + +/// The stealing half of the work-stealing deque. Stealers have access to the +/// opposite end of the deque from the worker, and they only have access to the +/// `steal` method. +/// +/// Stealers can be cloned to have more than one handle active at a time. +#[derive(Debug)] +pub struct Stealer { + deque: Arc>, +} + +/// When stealing some data, this is an enumeration of the possible outcomes. +#[derive(PartialEq, Eq, Debug)] +pub enum Steal { + /// The deque was empty at the time of stealing + Empty, + /// The stealer lost the race for stealing data, and a retry may return more + /// data. + Abort, + /// The stealer has successfully stolen some data. + Data(T), +} + +// An internal buffer used by the chase-lev deque. This structure is actually +// implemented as a circular buffer, and is used as the intermediate storage of +// the data in the deque. +// +// This Vec always has a length of 0, the backing buffer is just used by the +// code below. +struct Buffer { + storage: UnsafeCell>, + log_size: u32, +} + +impl fmt::Debug for Buffer { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Buffer {{ ... }}") + } +} + +impl Worker { + /// Pushes data onto the front of this work queue. + pub fn push(&self, t: T) { + unsafe { self.deque.push(t) } + } + + /// Pops data off the front of the work queue, returning `None` on an empty + /// queue. + pub fn try_pop(&self) -> Option { + unsafe { self.deque.try_pop() } + } +} + +impl Stealer { + /// Steals work off the end of the queue (opposite of the worker's end) + pub fn steal(&self) -> Steal { + self.deque.steal() + } +} + +impl Clone for Stealer { + fn clone(&self) -> Stealer { + Stealer { deque: self.deque.clone() } + } +} + +/// Creates a new empty deque +pub fn deque() -> (Worker, Stealer) { + let a = Arc::new(Deque::new()); + let b = a.clone(); + (Worker { deque: a, marker: PhantomData }, Stealer { deque: b }) +} + +// Almost all of this code can be found directly in the paper so I'm not +// personally going to heavily comment what's going on here. + +impl Deque { + fn new() -> Deque { + let array = Atomic::null(); + array.store(Some(Owned::new(Buffer::new(MIN_BITS))), SeqCst); + Deque { + bottom: AtomicIsize::new(0), + top: AtomicIsize::new(0), + array: array, + } + } + + unsafe fn push(&self, data: T) { + let guard = epoch::pin(); + + let mut b = self.bottom.load(Relaxed); + let t = self.top.load(Acquire); + let mut a = self.array.load(Relaxed, &guard).unwrap(); + + let size = b - t; + if size >= (a.size() as isize) - 1 { + // You won't find this code in the chase-lev deque paper. This is + // alluded to in a small footnote, however. We always free a buffer + // when growing in order to prevent leaks. + a = self.swap_buffer(a, a.resize(b, t, 1), &guard); + + // reload the bottom counter, since swap_buffer modifies it. + b = self.bottom.load(Relaxed); + } + a.put(b, data); + fence(Release); + self.bottom.store(b + 1, Relaxed); + } + + unsafe fn try_pop(&self) -> Option { + let guard = epoch::pin(); + + let b = self.bottom.load(Relaxed); + let a = self.array.load(Relaxed, &guard).unwrap(); + self.bottom.store(b - 1, Relaxed); + fence(SeqCst); // the store to bottom must occur before loading top. + let t = self.top.load(Relaxed); + + let size = b - t; + + if size <= 0 { + // empty queue. revert the decrement of bottom. + self.bottom.store(b, Relaxed); + None + } else if size >= 2 { + // non-racy case. return the data + let data = a.get(b - 1); + self.maybe_shrink(b - 1, t, &guard); + Some(data) + } else { + // racy case. race against steals. + let success = self.top.compare_and_swap(t, t + 1, SeqCst) == t; + + // set the queue to a canonically empty state. + self.bottom.store(b, Relaxed); + + if success { + Some(a.get(t)) + } else { + None + } + } + } + + fn steal(&self) -> Steal { + let guard = epoch::pin(); + + let t = self.top.load(Relaxed); + fence(SeqCst); // top must be loaded before bottom. + let b = self.bottom.load(Acquire); + + let size = b - t; + if size <= 0 { + return Steal::Empty + } + + unsafe { + // while the paper uses a "consume" ordering here, the closest thing we have + // available is Acquire, which is strictly stronger. + let a = self.array.load(Acquire, &guard).unwrap(); + let data = a.get(t); + // we may be racing against other steals and a pop. + if self.top.compare_and_swap(t, t + 1, SeqCst) == t { + Steal::Data(data) + } else { + mem::forget(data); // someone else stole this value + Steal::Abort + } + } + } + + // potentially shrink the array. This can be called only from the worker. + unsafe fn maybe_shrink(&self, b: isize, t: isize, guard: &epoch::Guard) { + let a = self.array.load(SeqCst, guard).unwrap(); + let size = b - t; + if size < (a.size() as isize) / K && size > (1 << MIN_BITS) { + self.swap_buffer(a, a.resize(b, t, -1), guard); + } + } + + // Helper routine not mentioned in the paper which is used in growing and + // shrinking buffers to swap in a new buffer into place. + // + // As a bit of a recap, stealers can continue using buffers after this + // method has called 'unlinked' on it. The continued usage is simply a read + // followed by a forget, but we must make sure that the memory can continue + // to be read after we flag this buffer for reclamation. All stealers, + // however, have their own epoch pinned during this time so the buffer will + // just naturally be free'd once all concurrent stealers have exited. + // + // This method may only be called safely from the workers due to the way it modifies + // the array pointer. + unsafe fn swap_buffer<'a>(&self, + old: Shared<'a, Buffer>, + buf: Buffer, + guard: &'a epoch::Guard) + -> Shared<'a, Buffer> { + let newbuf = Owned::new(buf); + let newbuf = self.array.store_and_ref(newbuf, Release, &guard); + guard.unlinked(old); + + newbuf + } +} + + +impl Drop for Deque { + fn drop(&mut self) { + let guard = epoch::pin(); + + // Arc enforces that we have truly exclusive access here. + + let t = self.top.load(Relaxed); + let b = self.bottom.load(Relaxed); + let a = self.array.swap(None, Relaxed, &guard).unwrap(); + // Free whatever is leftover in the dequeue, then free the backing + // memory itself + unsafe { + for i in t..b { + drop(a.get(i)); + } + guard.unlinked(a); + } + } +} + +impl Buffer { + fn new(log_size: u32) -> Buffer { + Buffer { + storage: UnsafeCell::new(Vec::with_capacity(1 << log_size)), + log_size: log_size, + } + } + + fn size(&self) -> usize { + unsafe { (*self.storage.get()).capacity() } + } + + fn mask(&self) -> isize { + unsafe { + ((*self.storage.get()).capacity() - 1) as isize + } + } + + unsafe fn elem(&self, i: isize) -> *mut T { + (*self.storage.get()).as_mut_ptr().offset(i & self.mask()) + } + + // This does not protect against loading duplicate values of the same cell, + // nor does this clear out the contents contained within. Hence, this is a + // very unsafe method which the caller needs to treat specially in case a + // race is lost. + unsafe fn get(&self, i: isize) -> T { + ptr::read(self.elem(i)) + } + + // Unsafe because this unsafely overwrites possibly uninitialized or + // initialized data. + unsafe fn put(&self, i: isize, t: T) { + ptr::write(self.elem(i), t); + } + + // Again, unsafe because this has incredibly dubious ownership violations. + // It is assumed that this buffer is immediately dropped. + unsafe fn resize(&self, b: isize, t: isize, delta: i32) -> Buffer { + let buf = Buffer::new(((self.log_size as i32) + delta) as u32); + for i in t..b { + buf.put(i, self.get(i)); + } + return buf; + } +} + +#[cfg(test)] +mod tests { + extern crate rand; + + use super::{deque, Worker, Stealer, Steal}; + + use std::thread; + use std::sync::Arc; + use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, + AtomicUsize, ATOMIC_USIZE_INIT}; + use std::sync::atomic::Ordering::SeqCst; + + use self::rand::Rng; + + #[test] + fn smoke() { + let (w, s) = deque(); + assert_eq!(w.try_pop(), None); + assert_eq!(s.steal(), Steal::Empty); + w.push(1); + assert_eq!(w.try_pop(), Some(1)); + w.push(1); + assert_eq!(s.steal(), Steal::Data(1)); + w.push(1); + assert_eq!(s.clone().steal(), Steal::Data(1)); + } + + #[test] + fn stealpush() { + static AMT: isize = 100000; + let (w, s) = deque(); + let t = thread::spawn(move || { + let mut left = AMT; + while left > 0 { + match s.steal() { + Steal::Data(i) => { + assert_eq!(i, 1); + left -= 1; + } + Steal::Abort | Steal::Empty => {} + } + } + }); + + for _ in 0..AMT { + w.push(1); + } + + t.join().unwrap(); + } + + #[test] + fn stealpush_large() { + static AMT: isize = 100000; + let (w, s) = deque(); + let t = thread::spawn(move || { + let mut left = AMT; + while left > 0 { + match s.steal() { + Steal::Data((1, 10)) => { left -= 1; } + Steal::Data(..) => panic!(), + Steal::Abort | Steal::Empty => {} + } + } + }); + + for _ in 0..AMT { + w.push((1, 10)); + } + + t.join().unwrap(); + } + + fn stampede(w: Worker>, + s: Stealer>, + nthreads: isize, + amt: usize) { + for _ in 0..amt { + w.push(Box::new(20)); + } + let remaining = Arc::new(AtomicUsize::new(amt)); + + let threads = (0..nthreads).map(|_| { + let remaining = remaining.clone(); + let s = s.clone(); + thread::spawn(move || { + while remaining.load(SeqCst) > 0 { + match s.steal() { + Steal::Data(val) => { + if *val == 20 { + remaining.fetch_sub(1, SeqCst); + } else { + panic!() + } + } + Steal::Abort | Steal::Empty => {} + } + } + }) + }).collect::>(); + + while remaining.load(SeqCst) > 0 { + if let Some(val) = w.try_pop() { + if *val == 20 { + remaining.fetch_sub(1, SeqCst); + } else { + panic!() + } + } + } + + for thread in threads.into_iter() { + thread.join().unwrap(); + } + } + + #[test] + fn run_stampede() { + let (w, s) = deque(); + stampede(w, s, 8, 10000); + } + + #[test] + fn many_stampede() { + static AMT: usize = 4; + let threads = (0..AMT).map(|_| { + let (w, s) = deque(); + thread::spawn(|| { + stampede(w, s, 4, 10000); + }) + }).collect::>(); + + for thread in threads.into_iter() { + thread.join().unwrap(); + } + } + + #[test] + fn stress() { + static AMT: isize = 100000; + static NTHREADS: isize = 8; + static DONE: AtomicBool = ATOMIC_BOOL_INIT; + static HITS: AtomicUsize = ATOMIC_USIZE_INIT; + let (w, s) = deque(); + + let threads = (0..NTHREADS).map(|_| { + let s = s.clone(); + thread::spawn(move || { + loop { + match s.steal() { + Steal::Data(2) => { HITS.fetch_add(1, SeqCst); } + Steal::Data(..) => panic!(), + _ if DONE.load(SeqCst) => break, + _ => {} + } + } + }) + }).collect::>(); + + let mut rng = rand::thread_rng(); + let mut expected = 0; + while expected < AMT { + if rng.gen_range(0, 3) == 2 { + match w.try_pop() { + None => {} + Some(2) => { HITS.fetch_add(1, SeqCst); }, + Some(_) => panic!(), + } + } else { + expected += 1; + w.push(2); + } + } + + while HITS.load(SeqCst) < AMT as usize { + match w.try_pop() { + None => {} + Some(2) => { HITS.fetch_add(1, SeqCst); }, + Some(_) => panic!(), + } + } + DONE.store(true, SeqCst); + + for thread in threads.into_iter() { + thread.join().unwrap(); + } + + assert_eq!(HITS.load(SeqCst), expected as usize); + } + + #[test] + fn no_starvation() { + static AMT: isize = 10000; + static NTHREADS: isize = 4; + static DONE: AtomicBool = ATOMIC_BOOL_INIT; + let (w, s) = deque(); + + let (threads, hits): (Vec<_>, Vec<_>) = (0..NTHREADS).map(|_| { + let s = s.clone(); + let ctr = Arc::new(AtomicUsize::new(0)); + let ctr2 = ctr.clone(); + (thread::spawn(move || { + loop { + match s.steal() { + Steal::Data((1, 2)) => { ctr.fetch_add(1, SeqCst); } + Steal::Data(..) => panic!(), + _ if DONE.load(SeqCst) => break, + _ => {} + } + } + }), ctr2) + }).unzip(); + + let mut rng = rand::thread_rng(); + let mut myhit = false; + 'outer: loop { + for _ in 0..rng.gen_range(0, AMT) { + if !myhit && rng.gen_range(0, 3) == 2 { + match w.try_pop() { + None => {} + Some((1, 2)) => myhit = true, + Some(_) => panic!(), + } + } else { + w.push((1, 2)); + } + } + + for slot in hits.iter() { + let amt = slot.load(SeqCst); + if amt == 0 { continue 'outer; } + } + if myhit { + break + } + } + + DONE.store(true, SeqCst); + + for thread in threads.into_iter() { + thread.join().unwrap(); + } + } +} diff --git a/crossbeam-0.3.2/src/sync/mod.rs b/crossbeam-0.3.2/src/sync/mod.rs new file mode 100644 index 000000000..bdb59cfe4 --- /dev/null +++ b/crossbeam-0.3.2/src/sync/mod.rs @@ -0,0 +1,14 @@ +//! Synchronization primitives. + +pub use self::ms_queue::MsQueue; +pub use self::atomic_option::AtomicOption; +pub use self::treiber_stack::TreiberStack; +pub use self::seg_queue::SegQueue; +pub use self::arc_cell::ArcCell; + +mod atomic_option; +mod ms_queue; +mod treiber_stack; +mod seg_queue; +pub mod chase_lev; +mod arc_cell; diff --git a/crossbeam-0.3.2/src/sync/ms_queue.rs b/crossbeam-0.3.2/src/sync/ms_queue.rs new file mode 100644 index 000000000..863741e19 --- /dev/null +++ b/crossbeam-0.3.2/src/sync/ms_queue.rs @@ -0,0 +1,526 @@ +use std::sync::atomic::Ordering::{Acquire, Release, Relaxed}; +use std::sync::atomic::AtomicBool; +use std::{ptr, mem}; +use std::thread::{self, Thread}; + +use epoch::{self, Atomic, Owned, Shared}; +use CachePadded; + +/// A Michael-Scott lock-free queue, with support for blocking `pop`s. +/// +/// Usable with any number of producers and consumers. +// The representation here is a singly-linked list, with a sentinel +// node at the front. In general the `tail` pointer may lag behind the +// actual tail. Non-sentinel nodes are either all `Data` or all +// `Blocked` (requests for data from blocked threads). +#[derive(Debug)] +pub struct MsQueue { + head: CachePadded>>, + tail: CachePadded>>, +} + +#[derive(Debug)] +struct Node { + payload: Payload, + next: Atomic>, +} + +#[derive(Debug)] +enum Payload { + /// A node with actual data that can be popped. + Data(T), + /// A node representing a blocked request for data. + Blocked(*mut Signal), +} + +/// A blocked request for data, which includes a slot to write the data. +#[derive(Debug)] +struct Signal { + /// Thread to unpark when data is ready. + thread: Thread, + /// The actual data, when available. + data: Option, + /// Is the data ready? Needed to cope with spurious wakeups. + ready: AtomicBool, +} + +impl Node { + fn is_data(&self) -> bool { + if let Payload::Data(_) = self.payload { true } else { false } + } +} + +// Any particular `T` should never accessed concurrently, so no need +// for Sync. +unsafe impl Sync for MsQueue {} +unsafe impl Send for MsQueue {} + +impl MsQueue { + /// Create a new, empty queue. + pub fn new() -> MsQueue { + let q = MsQueue { + head: CachePadded::new(Atomic::null()), + tail: CachePadded::new(Atomic::null()), + }; + let sentinel = Owned::new(Node { + payload: Payload::Data(unsafe { mem::uninitialized() }), + next: Atomic::null(), + }); + let guard = epoch::pin(); + let sentinel = q.head.store_and_ref(sentinel, Relaxed, &guard); + q.tail.store_shared(Some(sentinel), Relaxed); + q + } + + #[inline(always)] + /// Attempt to atomically place `n` into the `next` pointer of `onto`. + /// + /// If unsuccessful, returns ownership of `n`, possibly updating + /// the queue's `tail` pointer. + fn push_internal(&self, + guard: &epoch::Guard, + onto: Shared>, + n: Owned>) + -> Result<(), Owned>> + { + // is `onto` the actual tail? + if let Some(next) = onto.next.load(Acquire, guard) { + // if not, try to "help" by moving the tail pointer forward + self.tail.cas_shared(Some(onto), Some(next), Release); + Err(n) + } else { + // looks like the actual tail; attempt to link in `n` + onto.next.cas_and_ref(None, n, Release, guard).map(|shared| { + // try to move the tail pointer forward + self.tail.cas_shared(Some(onto), Some(shared), Release); + }) + } + } + + /// Add `t` to the back of the queue, possibly waking up threads + /// blocked on `pop`. + pub fn push(&self, t: T) { + /// We may or may not need to allocate a node; once we do, + /// we cache that allocation. + enum Cache { + Data(T), + Node(Owned>), + } + + impl Cache { + /// Extract the node if cached, or allocate if not. + fn into_node(self) -> Owned> { + match self { + Cache::Data(t) => { + Owned::new(Node { + payload: Payload::Data(t), + next: Atomic::null() + }) + } + Cache::Node(n) => n + } + } + + /// Extract the data from the cache, deallocating any cached node. + fn into_data(self) -> T { + match self { + Cache::Data(t) => t, + Cache::Node(node) => { + match node.into_inner().payload { + Payload::Data(t) => t, + _ => unreachable!(), + } + } + } + } + } + + let mut cache = Cache::Data(t); // don't allocate up front + let guard = epoch::pin(); + + loop { + // We push onto the tail, so we'll start optimistically by looking + // there first. + let tail = self.tail.load(Acquire, &guard).unwrap(); + + // Is the queue in Data mode (empty queues can be viewed as either mode)? + if tail.is_data() || + self.head.load(Relaxed, &guard).unwrap().as_raw() == tail.as_raw() + { + // Attempt to push onto the `tail` snapshot; fails if + // `tail.next` has changed, which will always be the case if the + // queue has transitioned to blocking mode. + match self.push_internal(&guard, tail, cache.into_node()) { + Ok(_) => return, + Err(n) => { + // replace the cache, retry whole thing + cache = Cache::Node(n) + } + } + } else { + // Queue is in blocking mode. Attempt to unblock a thread. + let head = self.head.load(Acquire, &guard).unwrap(); + // Get a handle on the first blocked node. Racy, so queue might + // be empty or in data mode by the time we see it. + let request = head.next.load(Acquire, &guard).and_then(|next| { + match next.payload { + Payload::Blocked(signal) => Some((next, signal)), + Payload::Data(_) => None, + } + }); + if let Some((blocked_node, signal)) = request { + // race to dequeue the node + if self.head.cas_shared(Some(head), Some(blocked_node), Release) { + unsafe { + // signal the thread + (*signal).data = Some(cache.into_data()); + let thread = (*signal).thread.clone(); + + (*signal).ready.store(true, Release); + thread.unpark(); + guard.unlinked(head); + return; + } + } + } + } + } + } + + #[inline(always)] + // Attempt to pop a data node. `Ok(None)` if queue is empty or in blocking + // mode; `Err(())` if lost race to pop. + fn pop_internal(&self, guard: &epoch::Guard) -> Result, ()> { + let head = self.head.load(Acquire, guard).unwrap(); + if let Some(next) = head.next.load(Acquire, guard) { + if let Payload::Data(ref t) = next.payload { + unsafe { + if self.head.cas_shared(Some(head), Some(next), Release) { + guard.unlinked(head); + Ok(Some(ptr::read(t))) + } else { + Err(()) + } + } + } else { + Ok(None) + } + } else { + Ok(None) + } + } + + /// Check if this queue is empty. + pub fn is_empty(&self) -> bool { + let guard = epoch::pin(); + let head = self.head.load(Acquire, &guard).unwrap(); + + if let Some(next) = head.next.load(Acquire, &guard) { + if let Payload::Data(_) = next.payload { + false + } else { + true + } + } else { + true + } + } + + /// Attempt to dequeue from the front. + /// + /// Returns `None` if the queue is observed to be empty. + pub fn try_pop(&self) -> Option { + let guard = epoch::pin(); + loop { + if let Ok(r) = self.pop_internal(&guard) { + return r; + } + } + } + + /// Dequeue an element from the front of the queue, blocking if the queue is + /// empty. + pub fn pop(&self) -> T { + let guard = epoch::pin(); + + // Fast path: keep retrying until we observe that the queue has no data, + // avoiding the allocation of a blocked node. + loop { + match self.pop_internal(&guard) { + Ok(Some(r)) => { + return r; + } + Ok(None) => { + break; + } + Err(()) => {} + } + } + + // The signal gets to live on the stack, since this stack frame will be + // blocked until receiving the signal. + let mut signal = Signal { + thread: thread::current(), + data: None, + ready: AtomicBool::new(false), + }; + + // Go ahead and allocate the blocked node; chances are, we'll need it. + let mut node = Owned::new(Node { + payload: Payload::Blocked(&mut signal), + next: Atomic::null(), + }); + + loop { + // try a normal pop + if let Ok(Some(r)) = self.pop_internal(&guard) { + return r; + } + + // At this point, we believe the queue is empty/blocked. + // Snapshot the tail, onto which we want to push a blocked node. + let tail = self.tail.load(Acquire, &guard).unwrap(); + + // Double-check that we're in blocking mode + if tail.is_data() { + // The current tail is in data mode, so we probably need to abort. + // BUT, it might be the sentinel, so check for that first. + let head = self.head.load(Relaxed, &guard).unwrap(); + if tail.is_data() && tail.as_raw() != head.as_raw() { continue; } + } + + // At this point, the tail snapshot is either a blocked node deep in + // the queue, the sentinel, or no longer accessible from the queue. + // In *ALL* of these cases, if we succeed in pushing onto the + // snapshot, we know we are maintaining the core invariant: all + // reachable, non-sentinel nodes have the same payload mode, in this + // case, blocked. + match self.push_internal(&guard, tail, node) { + Ok(()) => { + while !signal.ready.load(Acquire) { + thread::park(); + } + return signal.data.unwrap(); + } + Err(n) => { + node = n; + } + } + } + } +} + +impl Drop for MsQueue { + fn drop(&mut self) { + while self.try_pop().is_some() {} + + // Destroy the remaining sentinel node. + let guard = epoch::pin(); + let sentinel = self.head.load(Relaxed, &guard).unwrap().as_raw(); + unsafe { + drop(Vec::from_raw_parts(sentinel, 0, 1)); + } + } +} + +#[cfg(test)] +mod test { + const CONC_COUNT: i64 = 1000000; + + use scope; + use super::*; + + #[test] + fn push_try_pop_1() { + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + q.push(37); + assert!(!q.is_empty()); + assert_eq!(q.try_pop(), Some(37)); + assert!(q.is_empty()); + } + + #[test] + fn push_try_pop_2() { + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + q.push(37); + q.push(48); + assert_eq!(q.try_pop(), Some(37)); + assert!(!q.is_empty()); + assert_eq!(q.try_pop(), Some(48)); + assert!(q.is_empty()); + } + + #[test] + fn push_try_pop_many_seq() { + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + for i in 0..200 { + q.push(i) + } + assert!(!q.is_empty()); + for i in 0..200 { + assert_eq!(q.try_pop(), Some(i)); + } + assert!(q.is_empty()); + } + + #[test] + fn push_pop_1() { + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + q.push(37); + assert!(!q.is_empty()); + assert_eq!(q.pop(), 37); + assert!(q.is_empty()); + } + + #[test] + fn push_pop_2() { + let q: MsQueue = MsQueue::new(); + q.push(37); + q.push(48); + assert_eq!(q.pop(), 37); + assert_eq!(q.pop(), 48); + } + + #[test] + fn push_pop_many_seq() { + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + for i in 0..200 { + q.push(i) + } + assert!(!q.is_empty()); + for i in 0..200 { + assert_eq!(q.pop(), i); + } + assert!(q.is_empty()); + } + + #[test] + fn push_try_pop_many_spsc() { + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + + scope(|scope| { + scope.spawn(|| { + let mut next = 0; + + while next < CONC_COUNT { + if let Some(elem) = q.try_pop() { + assert_eq!(elem, next); + next += 1; + } + } + }); + + for i in 0..CONC_COUNT { + q.push(i) + } + }); + } + + #[test] + fn push_try_pop_many_spmc() { + fn recv(_t: i32, q: &MsQueue) { + let mut cur = -1; + for _i in 0..CONC_COUNT { + if let Some(elem) = q.try_pop() { + assert!(elem > cur); + cur = elem; + + if cur == CONC_COUNT - 1 { break } + } + } + } + + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + let qr = &q; + scope(|scope| { + for i in 0..3 { + scope.spawn(move || recv(i, qr)); + } + + scope.spawn(|| { + for i in 0..CONC_COUNT { + q.push(i); + } + }) + }); + } + + #[test] + fn push_try_pop_many_mpmc() { + enum LR { Left(i64), Right(i64) } + + let q: MsQueue = MsQueue::new(); + assert!(q.is_empty()); + + scope(|scope| { + for _t in 0..2 { + scope.spawn(|| { + for i in CONC_COUNT-1..CONC_COUNT { + q.push(LR::Left(i)) + } + }); + scope.spawn(|| { + for i in CONC_COUNT-1..CONC_COUNT { + q.push(LR::Right(i)) + } + }); + scope.spawn(|| { + let mut vl = vec![]; + let mut vr = vec![]; + for _i in 0..CONC_COUNT { + match q.try_pop() { + Some(LR::Left(x)) => vl.push(x), + Some(LR::Right(x)) => vr.push(x), + _ => {} + } + } + + let mut vl2 = vl.clone(); + let mut vr2 = vr.clone(); + vl2.sort(); + vr2.sort(); + + assert_eq!(vl, vl2); + assert_eq!(vr, vr2); + }); + } + }); + } + + #[test] + fn push_pop_many_spsc() { + let q: MsQueue = MsQueue::new(); + + scope(|scope| { + scope.spawn(|| { + let mut next = 0; + while next < CONC_COUNT { + assert_eq!(q.pop(), next); + next += 1; + } + }); + + for i in 0..CONC_COUNT { + q.push(i) + } + }); + assert!(q.is_empty()); + } + + #[test] + fn is_empty_dont_pop() { + let q: MsQueue = MsQueue::new(); + q.push(20); + q.push(20); + assert!(!q.is_empty()); + assert!(!q.is_empty()); + assert!(q.try_pop().is_some()); + } +} diff --git a/crossbeam-0.3.2/src/sync/seg_queue.rs b/crossbeam-0.3.2/src/sync/seg_queue.rs new file mode 100644 index 000000000..6135cabd5 --- /dev/null +++ b/crossbeam-0.3.2/src/sync/seg_queue.rs @@ -0,0 +1,289 @@ +use std::sync::atomic::Ordering::{Acquire, Release, Relaxed}; +use std::sync::atomic::{AtomicBool, AtomicUsize}; +use std::fmt; +use std::{ptr, mem}; +use std::cmp; +use std::cell::UnsafeCell; + +use epoch::{self, Atomic, Owned}; + +const SEG_SIZE: usize = 32; + +/// A Michael-Scott queue that allocates "segments" (arrays of nodes) +/// for efficiency. +/// +/// Usable with any number of producers and consumers. +#[derive(Debug)] +pub struct SegQueue { + head: Atomic>, + tail: Atomic>, +} + +struct Segment { + low: AtomicUsize, + data: [UnsafeCell<(T, AtomicBool)>; SEG_SIZE], + high: AtomicUsize, + next: Atomic>, +} + +impl fmt::Debug for Segment { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Segment {{ ... }}") + } +} + +unsafe impl Sync for Segment {} + +impl Segment { + fn new() -> Segment { + let rqueue = Segment { + data: unsafe { mem::uninitialized() }, + low: AtomicUsize::new(0), + high: AtomicUsize::new(0), + next: Atomic::null(), + }; + for val in rqueue.data.iter() { + unsafe { + (*val.get()).1 = AtomicBool::new(false); + } + } + rqueue + } +} + +impl SegQueue { + /// Create a new, empty queue. + pub fn new() -> SegQueue { + let q = SegQueue { + head: Atomic::null(), + tail: Atomic::null(), + }; + let sentinel = Owned::new(Segment::new()); + let guard = epoch::pin(); + let sentinel = q.head.store_and_ref(sentinel, Relaxed, &guard); + q.tail.store_shared(Some(sentinel), Relaxed); + q + } + + /// Add `t` to the back of the queue. + pub fn push(&self, t: T) { + let guard = epoch::pin(); + loop { + let tail = self.tail.load(Acquire, &guard).unwrap(); + if tail.high.load(Relaxed) >= SEG_SIZE { continue } + let i = tail.high.fetch_add(1, Relaxed); + unsafe { + if i < SEG_SIZE { + let cell = (*tail).data.get_unchecked(i).get(); + ptr::write(&mut (*cell).0, t); + (*cell).1.store(true, Release); + + if i + 1 == SEG_SIZE { + let tail = tail.next.store_and_ref(Owned::new(Segment::new()), Release, &guard); + self.tail.store_shared(Some(tail), Release); + } + + return + } + } + } + } + + /// Judge if the queue is empty. + /// + /// Returns `true` if the queue is empty. + pub fn is_empty(&self) -> bool { + let guard = epoch::pin(); + let head = self.head.load(Acquire, &guard).unwrap(); + let tail = self.tail.load(Acquire, &guard).unwrap(); + if head.as_raw() != tail.as_raw() { + return false; + } + + let low = head.low.load(Relaxed); + low >= cmp::min(head.high.load(Relaxed), SEG_SIZE) + } + + /// Attempt to dequeue from the front. + /// + /// Returns `None` if the queue is observed to be empty. + pub fn try_pop(&self) -> Option { + let guard = epoch::pin(); + loop { + let head = self.head.load(Acquire, &guard).unwrap(); + loop { + let low = head.low.load(Relaxed); + if low >= cmp::min(head.high.load(Relaxed), SEG_SIZE) { break } + if head.low.compare_and_swap(low, low+1, Relaxed) == low { + unsafe { + let cell = (*head).data.get_unchecked(low).get(); + loop { + if (*cell).1.load(Acquire) { break } + } + if low + 1 == SEG_SIZE { + loop { + if let Some(next) = head.next.load(Acquire, &guard) { + self.head.store_shared(Some(next), Release); + guard.unlinked(head); + break + } + } + } + return Some(ptr::read(&(*cell).0)) + } + } + } + if head.next.load(Relaxed, &guard).is_none() { return None } + } + } +} + +impl Drop for SegQueue { + fn drop(&mut self) { + while self.try_pop().is_some() {} + + // Destroy the remaining sentinel segment. + let guard = epoch::pin(); + let sentinel = self.head.load(Relaxed, &guard).unwrap().as_raw(); + unsafe { + drop(Vec::from_raw_parts(sentinel, 0, 1)); + } + } +} + +#[cfg(test)] +mod test { + const CONC_COUNT: i64 = 1000000; + + use scope; + use super::*; + + #[test] + fn push_pop_1() { + let q: SegQueue = SegQueue::new(); + q.push(37); + assert_eq!(q.try_pop(), Some(37)); + } + + #[test] + fn push_pop_2() { + let q: SegQueue = SegQueue::new(); + q.push(37); + q.push(48); + assert_eq!(q.try_pop(), Some(37)); + assert_eq!(q.try_pop(), Some(48)); + } + + #[test] + fn push_pop_empty_check() { + let q: SegQueue = SegQueue::new(); + assert_eq!(q.is_empty(), true); + q.push(42); + assert_eq!(q.is_empty(), false); + assert_eq!(q.try_pop(), Some(42)); + assert_eq!(q.is_empty(), true); + } + + #[test] + fn push_pop_many_seq() { + let q: SegQueue = SegQueue::new(); + for i in 0..200 { + q.push(i) + } + for i in 0..200 { + assert_eq!(q.try_pop(), Some(i)); + } + } + + #[test] + fn push_pop_many_spsc() { + let q: SegQueue = SegQueue::new(); + + scope(|scope| { + scope.spawn(|| { + let mut next = 0; + + while next < CONC_COUNT { + if let Some(elem) = q.try_pop() { + assert_eq!(elem, next); + next += 1; + } + } + }); + + for i in 0..CONC_COUNT { + q.push(i) + } + }); + } + + #[test] + fn push_pop_many_spmc() { + fn recv(_t: i32, q: &SegQueue) { + let mut cur = -1; + for _i in 0..CONC_COUNT { + if let Some(elem) = q.try_pop() { + assert!(elem > cur); + cur = elem; + + if cur == CONC_COUNT - 1 { break } + } + } + } + + let q: SegQueue = SegQueue::new(); + let qr = &q; + scope(|scope| { + for i in 0..3 { + scope.spawn(move || recv(i, qr)); + } + + scope.spawn(|| { + for i in 0..CONC_COUNT { + q.push(i); + } + }) + }); + } + + #[test] + fn push_pop_many_mpmc() { + enum LR { Left(i64), Right(i64) } + + let q: SegQueue = SegQueue::new(); + + scope(|scope| { + for _t in 0..2 { + scope.spawn(|| { + for i in CONC_COUNT-1..CONC_COUNT { + q.push(LR::Left(i)) + } + }); + scope.spawn(|| { + for i in CONC_COUNT-1..CONC_COUNT { + q.push(LR::Right(i)) + } + }); + scope.spawn(|| { + let mut vl = vec![]; + let mut vr = vec![]; + for _i in 0..CONC_COUNT { + match q.try_pop() { + Some(LR::Left(x)) => vl.push(x), + Some(LR::Right(x)) => vr.push(x), + _ => {} + } + } + + let mut vl2 = vl.clone(); + let mut vr2 = vr.clone(); + vl2.sort(); + vr2.sort(); + + assert_eq!(vl, vl2); + assert_eq!(vr, vr2); + }); + } + }); + } +} diff --git a/crossbeam-0.3.2/src/sync/treiber_stack.rs b/crossbeam-0.3.2/src/sync/treiber_stack.rs new file mode 100644 index 000000000..0c5f9096b --- /dev/null +++ b/crossbeam-0.3.2/src/sync/treiber_stack.rs @@ -0,0 +1,110 @@ +use std::sync::atomic::Ordering::{Acquire, Release, Relaxed}; +use std::ptr; + +use epoch::{self, Atomic, Owned}; + +/// Treiber's lock-free stack. +/// +/// Usable with any number of producers and consumers. +#[derive(Debug)] +pub struct TreiberStack { + head: Atomic>, +} + +#[derive(Debug)] +struct Node { + data: T, + next: Atomic>, +} + +impl TreiberStack { + /// Create a new, empty stack. + pub fn new() -> TreiberStack { + TreiberStack { head: Atomic::null() } + } + + /// Push `t` on top of the stack. + pub fn push(&self, t: T) { + let mut n = Owned::new(Node { + data: t, + next: Atomic::null(), + }); + let guard = epoch::pin(); + loop { + let head = self.head.load(Relaxed, &guard); + n.next.store_shared(head, Relaxed); + match self.head.cas_and_ref(head, n, Release, &guard) { + Ok(_) => break, + Err(owned) => n = owned, + } + } + } + + /// Attempt to pop the top element of the stack. + /// **Deprecated method**, use try_pop + /// + /// Returns `None` if the stack is observed to be empty. + #[cfg_attr(any(feature="beta", feature="nightly"), deprecated(note="The pop method has been renamed to try_pop for consistency with other collections."))] + pub fn pop(&self) -> Option { + self.try_pop() + } + + /// Attempt to pop the top element of the stack. + /// + /// Returns `None` if the stack is observed to be empty. + pub fn try_pop(&self) -> Option { + let guard = epoch::pin(); + loop { + match self.head.load(Acquire, &guard) { + Some(head) => { + let next = head.next.load(Relaxed, &guard); + if self.head.cas_shared(Some(head), next, Release) { + unsafe { + guard.unlinked(head); + return Some(ptr::read(&(*head).data)); + } + } + } + None => return None, + } + } + } + + /// Check if this queue is empty. + pub fn is_empty(&self) -> bool { + let guard = epoch::pin(); + self.head.load(Acquire, &guard).is_none() + } +} + +impl Drop for TreiberStack { + fn drop(&mut self) { + while self.try_pop().is_some() {} + } +} + +impl Default for TreiberStack { + fn default() -> Self { + TreiberStack::new() + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn is_empty() { + let q: TreiberStack = TreiberStack::new(); + assert!(q.is_empty()); + q.push(20); + q.push(20); + assert!(!q.is_empty()); + assert!(!q.is_empty()); + assert!(q.try_pop().is_some()); + assert!(q.try_pop().is_some()); + assert!(q.is_empty()); + q.push(25); + assert!(!q.is_empty()); + } +} diff --git a/crypt32-sys-0.2.0/.cargo-checksum.json b/crypt32-sys-0.2.0/.cargo-checksum.json new file mode 100644 index 000000000..76b310692 --- /dev/null +++ b/crypt32-sys-0.2.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"e34988f7e069e0b2f3bfc064295161e489b2d4e04a2e4248fb94360cdf00b4ec"} \ No newline at end of file diff --git a/crypt32-sys-0.2.0/Cargo.toml b/crypt32-sys-0.2.0/Cargo.toml new file mode 100644 index 000000000..9a0f6c620 --- /dev/null +++ b/crypt32-sys-0.2.0/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "crypt32-sys" +version = "0.2.0" +authors = ["Peter Atashian "] +description = "Contains function definitions for the Windows API library crypt32. See winapi for types and constants." +documentation = "https://retep998.github.io/doc/crypt32/" +repository = "https://github.com/retep998/winapi-rs" +readme = "README.md" +keywords = ["windows", "ffi", "win32"] +license = "MIT" +build = "build.rs" +links = "crypt32" +[lib] +name = "crypt32" +[dependencies] +winapi = { version = "0.2.4", path = "../.." } +[build-dependencies] +winapi-build = { version = "0.1.1", path = "../../build" } diff --git a/crypt32-sys-0.2.0/README.md b/crypt32-sys-0.2.0/README.md new file mode 100644 index 000000000..2f4180249 --- /dev/null +++ b/crypt32-sys-0.2.0/README.md @@ -0,0 +1,13 @@ +# crypt32 # +Contains function definitions for the Windows API library crypt32. See winapi for types and constants. + +```toml +[dependencies] +crypt32-sys = "0.0.1" +``` + +```rust +extern crate crypt32; +``` + +[Documentation](https://retep998.github.io/doc/crypt32/) diff --git a/crypt32-sys-0.2.0/build.rs b/crypt32-sys-0.2.0/build.rs new file mode 100644 index 000000000..0f17d14e5 --- /dev/null +++ b/crypt32-sys-0.2.0/build.rs @@ -0,0 +1,6 @@ +// Copyright © 2015, Peter Atashian +// Licensed under the MIT License +extern crate build; +fn main() { + build::link("crypt32", false) +} diff --git a/crypt32-sys-0.2.0/src/lib.rs b/crypt32-sys-0.2.0/src/lib.rs new file mode 100644 index 000000000..0dc63e519 --- /dev/null +++ b/crypt32-sys-0.2.0/src/lib.rs @@ -0,0 +1,796 @@ +// Copyright © 2015, Peter Atashian +// Licensed under the MIT License +//! FFI bindings to crypt32. +#![cfg(windows)] +extern crate winapi; +use winapi::*; +extern "system" { + pub fn CertAddCRLContextToStore( + hCertStore: HCERTSTORE, pCrlContext: PCCRL_CONTEXT, dwAddDisposition: DWORD, + ppStoreContext: *mut PCCRL_CONTEXT, + ) -> BOOL; + pub fn CertAddCRLLinkToStore( + hCertStore: HCERTSTORE, pCrlContext: PCCRL_CONTEXT, dwAddDisposition: DWORD, + ppStoreContext: *mut PCCRL_CONTEXT, + ) -> BOOL; + pub fn CertAddCTLContextToStore( + hCertStore: HCERTSTORE, pCtlContext: PCCTL_CONTEXT, dwAddDisposition: DWORD, + ppStoreContext: *mut PCCTL_CONTEXT, + ) -> BOOL; + pub fn CertAddCTLLinkToStore( + hCertStore: HCERTSTORE, pCtlContext: PCCTL_CONTEXT, dwAddDisposition: DWORD, + ppStoreContext: *mut PCCTL_CONTEXT, + ) -> BOOL; + pub fn CertAddCertificateContextToStore( + hCertStore: HCERTSTORE, pCertContext: PCCERT_CONTEXT, dwAddDisposition: DWORD, + ppStoreContext: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CertAddCertificateLinkToStore( + hCertStore: HCERTSTORE, pCertContext: PCCERT_CONTEXT, dwAddDisposition: DWORD, + ppStoreContext: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CertAddEncodedCRLToStore( + hCertStore: HCERTSTORE, dwCertEncodingType: DWORD, pbCrlEncoded: *const BYTE, + cbCrlEncoded: DWORD, dwAddDisposition: DWORD, ppCrlContext: *mut PCCRL_CONTEXT, + ) -> BOOL; + pub fn CertAddEncodedCTLToStore( + hCertStore: HCERTSTORE, dwMsgAndCertEncodingType: DWORD, pbCtlEncoded: *const BYTE, + cbCtlEncoded: DWORD, dwAddDisposition: DWORD, ppCtlContext: *mut PCCTL_CONTEXT, + ) -> BOOL; + pub fn CertAddEncodedCertificateToStore( + hCertStore: HCERTSTORE, dwCertEncodingType: DWORD, pbCertEncoded: *const BYTE, + cbCertEncoded: DWORD, dwAddDisposition: DWORD, ppCertContext: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CertAddEncodedCertificateToSystemStoreA( + szCertStoreName: LPCSTR, pbCertEncoded: *const BYTE, cbCertEncoded: DWORD, + ) -> BOOL; + pub fn CertAddEncodedCertificateToSystemStoreW( + szCertStoreName: LPCWSTR, pbCertEncoded: *const BYTE, cbCertEncoded: DWORD, + ) -> BOOL; + pub fn CertAddEnhancedKeyUsageIdentifier( + pCertContext: PCCERT_CONTEXT, pszUsageIdentifier: LPCSTR, + ) -> BOOL; + pub fn CertAddRefServerOcspResponse(hServerOcspResponse: HCERT_SERVER_OCSP_RESPONSE); + pub fn CertAddRefServerOcspResponseContext( + pServerOcspResponseContext: PCCERT_SERVER_OCSP_RESPONSE_CONTEXT, + ); + pub fn CertAddSerializedElementToStore( + hCertStore: HCERTSTORE, pbElement: *const BYTE, cbElement: DWORD, dwAddDisposition: DWORD, + dwFlags: DWORD, dwContextTypeFlags: DWORD, pdwContextType: *mut DWORD, + ppvContext: *mut *const c_void, + ) -> BOOL; + pub fn CertAddStoreToCollection( + hCollectionStore: HCERTSTORE, hSiblingStore: HCERTSTORE, dwUpdateFlags: DWORD, + dwPriority: DWORD, + ) -> BOOL; + pub fn CertAlgIdToOID(dwAlgId: DWORD) -> LPCSTR; + pub fn CertCloseServerOcspResponse( + hServerOcspResponse: HCERT_SERVER_OCSP_RESPONSE, dwFlags: DWORD, + ); + pub fn CertCloseStore(hCertStore: HCERTSTORE, dwFlags: DWORD) -> BOOL; + pub fn CertCompareCertificate( + dwCertEncodingType: DWORD, pCertId1: PCERT_INFO, pCertId2: PCERT_INFO, + ) -> BOOL; + pub fn CertCompareCertificateName( + dwCertEncodingType: DWORD, pCertName1: PCERT_NAME_BLOB, pCertName2: PCERT_NAME_BLOB, + ) -> BOOL; + pub fn CertCompareIntegerBlob(pInt1: PCRYPT_INTEGER_BLOB, pInt2: PCRYPT_INTEGER_BLOB) -> BOOL; + pub fn CertComparePublicKeyInfo( + dwCertEncodingType: DWORD, pPublicKey1: PCERT_PUBLIC_KEY_INFO, + pPublicKey2: PCERT_PUBLIC_KEY_INFO, + ) -> BOOL; + pub fn CertControlStore( + hCertStore: HCERTSTORE, dwFlags: DWORD, dwCtrlType: DWORD, pvCtrlPara: *const c_void, + ) -> BOOL; + pub fn CertCreateCRLContext( + dwCertEncodingType: DWORD, pbCrlEncoded: *const BYTE, cbCrlEncoded: DWORD, + ) -> PCCRL_CONTEXT; + pub fn CertCreateCTLContext( + dwMsgAndCertEncodingType: DWORD, pbCtlEncoded: *const BYTE, cbCtlEncoded: DWORD, + ) -> PCCTL_CONTEXT; + pub fn CertCreateCTLEntryFromCertificateContextProperties( + pCertContext: PCCERT_CONTEXT, cOptAttr: DWORD, rgOptAttr: PCRYPT_ATTRIBUTE, dwFlags: DWORD, + pvReserved: *mut c_void, pCtlEntry: PCTL_ENTRY, pcbCtlEntry: *mut DWORD, + ) -> BOOL; + pub fn CertCreateCertificateChainEngine( + pConfig: PCERT_CHAIN_ENGINE_CONFIG, phChainEngine: *mut HCERTCHAINENGINE, + ) -> BOOL; + pub fn CertCreateCertificateContext( + dwCertEncodingType: DWORD, pbCertEncoded: *const BYTE, cbCertEncoded: DWORD, + ) -> PCCERT_CONTEXT; + pub fn CertCreateContext( + dwContextType: DWORD, dwEncodingType: DWORD, pbEncoded: *const BYTE, cbEncoded: DWORD, + dwFlags: DWORD, pCreatePara: PCERT_CREATE_CONTEXT_PARA, + ) -> *const c_void; + pub fn CertCreateSelfSignCertificate( + hCryptProvOrNCryptKey: HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, pSubjectIssuerBlob: PCERT_NAME_BLOB, + dwFlags: DWORD, pKeyProvInfo: PCRYPT_KEY_PROV_INFO, + pSignatureAlgorithm: PCRYPT_ALGORITHM_IDENTIFIER, pStartTime: PSYSTEMTIME, + pEndTime: PSYSTEMTIME, pExtensions: PCERT_EXTENSIONS, + ) -> PCCERT_CONTEXT; + pub fn CertDeleteCRLFromStore(pCrlContext: PCCRL_CONTEXT) -> BOOL; + pub fn CertDeleteCTLFromStore(pCtlContext: PCCTL_CONTEXT) -> BOOL; + pub fn CertDeleteCertificateFromStore(pCertContext: PCCERT_CONTEXT) -> BOOL; + pub fn CertDuplicateCRLContext(pCrlContext: PCCRL_CONTEXT) -> PCCRL_CONTEXT; + pub fn CertDuplicateCTLContext(pCtlContext: PCCTL_CONTEXT) -> PCCTL_CONTEXT; + pub fn CertDuplicateCertificateChain( + pChainContext: PCCERT_CHAIN_CONTEXT, + ) -> PCCERT_CHAIN_CONTEXT; + pub fn CertDuplicateCertificateContext(pCertContext: PCCERT_CONTEXT) -> PCCERT_CONTEXT; + pub fn CertDuplicateStore(hCertStore: HCERTSTORE) -> HCERTSTORE; + pub fn CertEnumCRLContextProperties(pCrlContext: PCCRL_CONTEXT, dwPropId: DWORD) -> DWORD; + pub fn CertEnumCRLsInStore( + hCertStore: HCERTSTORE, pPrevCrlContext: PCCRL_CONTEXT, + ) -> PCCRL_CONTEXT; + pub fn CertEnumCTLContextProperties(pCtlContext: PCCTL_CONTEXT, dwPropId: DWORD) -> DWORD; + pub fn CertEnumCTLsInStore( + hCertStore: HCERTSTORE, pPrevCtlContext: PCCTL_CONTEXT, + ) -> PCCTL_CONTEXT; + pub fn CertEnumCertificateContextProperties( + pCertContext: PCCERT_CONTEXT, dwPropId: DWORD, + ) -> DWORD; + pub fn CertEnumCertificatesInStore( + hCertStore: HCERTSTORE, pPrevCertContext: PCCERT_CONTEXT, + ) -> PCCERT_CONTEXT; + pub fn CertEnumPhysicalStore( + pvSystemStore: *const c_void, dwFlags: DWORD, pvArg: *mut c_void, + pfnEnum: PFN_CERT_ENUM_PHYSICAL_STORE, + ) -> BOOL; + pub fn CertEnumSubjectInSortedCTL( + pCtlContext: PCCTL_CONTEXT, ppvNextSubject: *mut *mut c_void, + pSubjectIdentifier: PCRYPT_DER_BLOB, pEncodedAttributes: PCRYPT_DER_BLOB, + ) -> BOOL; + pub fn CertEnumSystemStore( + dwFlags: DWORD, pvSystemStoreLocationPara: *mut c_void, pvArg: *mut c_void, + pfnEnum: PFN_CERT_ENUM_SYSTEM_STORE, + ) -> BOOL; + pub fn CertEnumSystemStoreLocation( + dwFlags: DWORD, pvArg: *mut c_void, pfnEnum: PFN_CERT_ENUM_SYSTEM_STORE_LOCATION, + ) -> BOOL; + pub fn CertFindAttribute( + pszObjId: LPCSTR, cAttr: DWORD, rgAttr: *mut CRYPT_ATTRIBUTE, + ) -> PCRYPT_ATTRIBUTE; + pub fn CertFindCRLInStore( + hCertStore: HCERTSTORE, dwCertEncodingType: DWORD, dwFindFlags: DWORD, dwFindType: DWORD, + pvFindPara: *const c_void, pPrevCrlContext: PCCRL_CONTEXT, + ) -> PCCRL_CONTEXT; + pub fn CertFindCTLInStore( + hCertStore: HCERTSTORE, dwMsgAndCertEncodingType: DWORD, dwFindFlags: DWORD, + dwFindType: DWORD, pvFindPara: *const c_void, pPrevCtlContext: PCCTL_CONTEXT, + ) -> PCCTL_CONTEXT; + pub fn CertFindCertificateInCRL( + pCert: PCCERT_CONTEXT, pCrlContext: PCCRL_CONTEXT, dwFlags: DWORD, pvReserved: *mut c_void, + ppCrlEntry: *mut PCRL_ENTRY, + ) -> BOOL; + pub fn CertFindCertificateInStore( + hCertStore: HCERTSTORE, dwCertEncodingType: DWORD, dwFindFlags: DWORD, dwFindType: DWORD, + pvFindPara: *const c_void, pPrevCertContext: PCCERT_CONTEXT, + ) -> PCCERT_CONTEXT; + pub fn CertFindChainInStore( + hCertStore: HCERTSTORE, dwCertEncodingType: DWORD, dwFindFlags: DWORD, dwFindType: DWORD, + pvFindPara: *const c_void, pPrevChainContext: PCCERT_CHAIN_CONTEXT, + ) -> PCCERT_CHAIN_CONTEXT; + pub fn CertFindExtension( + pszObjId: LPCSTR, cExtensions: DWORD, rgExtensions: *mut CERT_EXTENSION, + ) -> PCERT_EXTENSION; + pub fn CertFindRDNAttr(pszObjId: LPCSTR, pName: PCERT_NAME_INFO) -> PCERT_RDN_ATTR; + pub fn CertFindSubjectInCTL( + dwEncodingType: DWORD, dwSubjectType: DWORD, pvSubject: *mut c_void, + pCtlContext: PCCTL_CONTEXT, dwFlags: DWORD, + ) -> PCTL_ENTRY; + pub fn CertFindSubjectInSortedCTL( + pSubjectIdentifier: PCRYPT_DATA_BLOB, pCtlContext: PCCTL_CONTEXT, dwFlags: DWORD, + pvReserved: *mut c_void, pEncodedAttributes: PCRYPT_DER_BLOB, + ) -> BOOL; + pub fn CertFreeCRLContext(pCrlContext: PCCRL_CONTEXT) -> BOOL; + pub fn CertFreeCTLContext(pCtlContext: PCCTL_CONTEXT) -> BOOL; + pub fn CertFreeCertificateChain(pChainContext: PCCERT_CHAIN_CONTEXT); + pub fn CertFreeCertificateChainEngine(hChainEngine: HCERTCHAINENGINE); + pub fn CertFreeCertificateChainList(prgpSelection: *mut PCCERT_CHAIN_CONTEXT); + pub fn CertFreeCertificateContext(pCertContext: PCCERT_CONTEXT) -> BOOL; + pub fn CertFreeServerOcspResponseContext( + pServerOcspResponseContext: PCCERT_SERVER_OCSP_RESPONSE_CONTEXT, + ); + pub fn CertGetCRLContextProperty( + pCrlContext: PCCRL_CONTEXT, dwPropId: DWORD, pvData: *mut c_void, pcbData: *mut DWORD, + ) -> BOOL; + pub fn CertGetCRLFromStore( + hCertStore: HCERTSTORE, pIssuerContext: PCCERT_CONTEXT, pPrevCrlContext: PCCRL_CONTEXT, + pdwFlags: *mut DWORD, + ) -> PCCRL_CONTEXT; + pub fn CertGetCTLContextProperty( + pCtlContext: PCCTL_CONTEXT, dwPropId: DWORD, pvData: *mut c_void, pcbData: *mut DWORD, + ) -> BOOL; + pub fn CertGetCertificateChain( + hChainEngine: HCERTCHAINENGINE, pCertContext: PCCERT_CONTEXT, pTime: LPFILETIME, + hAdditionalStore: HCERTSTORE, pChainPara: PCERT_CHAIN_PARA, dwFlags: DWORD, + pvReserved: LPVOID, ppChainContext: *mut PCCERT_CHAIN_CONTEXT, + ) -> BOOL; + pub fn CertGetCertificateContextProperty( + pCertContext: PCCERT_CONTEXT, dwPropId: DWORD, pvData: *mut c_void, pcbData: *mut DWORD, + ) -> BOOL; + pub fn CertGetEnhancedKeyUsage( + pCertContext: PCCERT_CONTEXT, dwFlags: DWORD, pUsage: PCERT_ENHKEY_USAGE, + pcbUsage: *mut DWORD, + ) -> BOOL; + pub fn CertGetIntendedKeyUsage( + dwCertEncodingType: DWORD, pCertInfo: PCERT_INFO, pbKeyUsage: *mut BYTE, cbKeyUsage: DWORD, + ) -> BOOL; + pub fn CertGetIssuerCertificateFromStore( + hCertStore: HCERTSTORE, pSubjectContext: PCCERT_CONTEXT, pPrevIssuerContext: PCCERT_CONTEXT, + pdwFlags: *mut DWORD, + ) -> PCCERT_CONTEXT; + pub fn CertGetNameStringA( + pCertContext: PCCERT_CONTEXT, dwType: DWORD, dwFlags: DWORD, pvTypePara: *mut c_void, + pszNameString: LPSTR, cchNameString: DWORD, + ) -> DWORD; + pub fn CertGetNameStringW( + pCertContext: PCCERT_CONTEXT, dwType: DWORD, dwFlags: DWORD, pvTypePara: *mut c_void, + pszNameString: LPWSTR, cchNameString: DWORD, + ) -> DWORD; + pub fn CertGetPublicKeyLength( + dwCertEncodingType: DWORD, pPublicKey: PCERT_PUBLIC_KEY_INFO, + ) -> DWORD; + pub fn CertGetServerOcspResponseContext( + hServerOcspResponse: HCERT_SERVER_OCSP_RESPONSE, dwFlags: DWORD, pvReserved: LPVOID, + ) -> PCCERT_SERVER_OCSP_RESPONSE_CONTEXT; + pub fn CertGetStoreProperty( + hCertStore: HCERTSTORE, dwPropId: DWORD, pvData: *mut c_void, pcbData: *mut DWORD, + ) -> BOOL; + pub fn CertGetSubjectCertificateFromStore( + hCertStore: HCERTSTORE, dwCertEncodingType: DWORD, pCertId: PCERT_INFO, + ) -> PCCERT_CONTEXT; + pub fn CertGetValidUsages( + cCerts: DWORD, rghCerts: *mut PCCERT_CONTEXT, cNumOIDs: *mut c_int, rghOIDs: *mut LPSTR, + pcbOIDs: *mut DWORD, + ) -> BOOL; + pub fn CertIsRDNAttrsInCertificateName( + dwCertEncodingType: DWORD, dwFlags: DWORD, pCertName: PCERT_NAME_BLOB, pRDN: PCERT_RDN, + ) -> BOOL; + pub fn CertIsStrongHashToSign( + pStrongSignPara: PCCERT_STRONG_SIGN_PARA, pwszCNGHashAlgid: LPCWSTR, + pSigningCert: PCCERT_CONTEXT, + ) -> BOOL; + pub fn CertIsValidCRLForCertificate( + pCert: PCCERT_CONTEXT, pCrl: PCCRL_CONTEXT, dwFlags: DWORD, pvReserved: *mut c_void, + ) -> BOOL; + pub fn CertNameToStrA( + dwCertEncodingType: DWORD, pName: PCERT_NAME_BLOB, dwStrType: DWORD, psz: LPSTR, csz: DWORD, + ) -> DWORD; + pub fn CertNameToStrW( + dwCertEncodingType: DWORD, pName: PCERT_NAME_BLOB, dwStrType: DWORD, psz: LPWSTR, + csz: DWORD, + ) -> DWORD; + pub fn CertOIDToAlgId(pszObjId: LPCSTR) -> DWORD; + pub fn CertOpenServerOcspResponse( + pChainContext: PCCERT_CHAIN_CONTEXT, dwFlags: DWORD, pvReserved: LPVOID, + ) -> HCERT_SERVER_OCSP_RESPONSE; + pub fn CertOpenStore( + lpszStoreProvider: LPCSTR, dwEncodingType: DWORD, hCryptProv: HCRYPTPROV_LEGACY, + dwFlags: DWORD, pvPara: *const c_void, + ) -> HCERTSTORE; + pub fn CertOpenSystemStoreA( + hProv: HCRYPTPROV_LEGACY, szSubsystemProtocol: LPCSTR, + ) -> HCERTSTORE; + pub fn CertOpenSystemStoreW( + hProv: HCRYPTPROV_LEGACY, szSubsystemProtocol: LPCWSTR, + ) -> HCERTSTORE; + pub fn CertRDNValueToStrA( + dwValueType: DWORD, pValue: PCERT_RDN_VALUE_BLOB, psz: LPSTR, csz: DWORD, + ) -> DWORD; + pub fn CertRDNValueToStrW( + dwValueType: DWORD, pValue: PCERT_RDN_VALUE_BLOB, psz: LPWSTR, csz: DWORD, + ) -> DWORD; + pub fn CertRegisterPhysicalStore( + pvSystemStore: *const c_void, dwFlags: DWORD, pwszStoreName: LPCWSTR, + pStoreInfo: PCERT_PHYSICAL_STORE_INFO, pvReserved: *mut c_void, + ) -> BOOL; + pub fn CertRegisterSystemStore( + pvSystemStore: *const c_void, dwFlags: DWORD, pStoreInfo: PCERT_SYSTEM_STORE_INFO, + pvReserved: *mut c_void, + ) -> BOOL; + pub fn CertRemoveEnhancedKeyUsageIdentifier( + pCertContext: PCCERT_CONTEXT, pszUsageIdentifier: LPCSTR, + ) -> BOOL; + pub fn CertRemoveStoreFromCollection(hCollectionStore: HCERTSTORE, hSiblingStore: HCERTSTORE); + pub fn CertResyncCertificateChainEngine(hChainEngine: HCERTCHAINENGINE) -> BOOL; + pub fn CertRetrieveLogoOrBiometricInfo( + pCertContext: PCCERT_CONTEXT, lpszLogoOrBiometricType: LPCSTR, dwRetrievalFlags: DWORD, + dwTimeout: DWORD, dwFlags: DWORD, pvReserved: *mut c_void, ppbData: *mut *mut BYTE, + pcbData: *mut DWORD, ppwszMimeType: *mut LPWSTR, + ) -> BOOL; + pub fn CertSaveStore( + hCertStore: HCERTSTORE, dwEncodingType: DWORD, dwSaveAs: DWORD, dwSaveTo: DWORD, + pvSaveToPara: *mut c_void, dwFlags: DWORD, + ) -> BOOL; + pub fn CertSelectCertificateChains( + pSelectionContext: LPCGUID, dwFlags: DWORD, pChainParameters: PCCERT_SELECT_CHAIN_PARA, + cCriteria: DWORD, rgpCriteria: PCCERT_SELECT_CRITERIA, hStore: HCERTSTORE, + pcSelection: PDWORD, pprgpSelection: *mut *mut PCCERT_CHAIN_CONTEXT, + ) -> BOOL; + pub fn CertSerializeCRLStoreElement( + pCrlContext: PCCRL_CONTEXT, dwFlags: DWORD, pbElement: *mut BYTE, pcbElement: *mut DWORD, + ) -> BOOL; + pub fn CertSerializeCTLStoreElement( + pCtlContext: PCCTL_CONTEXT, dwFlags: DWORD, pbElement: *mut BYTE, pcbElement: *mut DWORD, + ) -> BOOL; + pub fn CertSerializeCertificateStoreElement( + pCertContext: PCCERT_CONTEXT, dwFlags: DWORD, pbElement: *mut BYTE, pcbElement: *mut DWORD, + ) -> BOOL; + pub fn CertSetCRLContextProperty( + pCrlContext: PCCRL_CONTEXT, dwPropId: DWORD, dwFlags: DWORD, pvData: *const c_void, + ) -> BOOL; + pub fn CertSetCTLContextProperty( + pCtlContext: PCCTL_CONTEXT, dwPropId: DWORD, dwFlags: DWORD, pvData: *const c_void, + ) -> BOOL; + pub fn CertSetCertificateContextPropertiesFromCTLEntry( + pCertContext: PCCERT_CONTEXT, pCtlEntry: PCTL_ENTRY, dwFlags: DWORD, + ) -> BOOL; + pub fn CertSetCertificateContextProperty( + pCertContext: PCCERT_CONTEXT, dwPropId: DWORD, dwFlags: DWORD, pvData: *const c_void, + ) -> BOOL; + pub fn CertSetEnhancedKeyUsage( + pCertContext: PCCERT_CONTEXT, pUsage: PCERT_ENHKEY_USAGE, + ) -> BOOL; + pub fn CertSetStoreProperty( + hCertStore: HCERTSTORE, dwPropId: DWORD, dwFlags: DWORD, pvData: *const c_void, + ) -> BOOL; + pub fn CertStrToNameA( + dwCertEncodingType: DWORD, pszX500: LPCSTR, dwStrType: DWORD, pvReserved: *mut c_void, + pbEncoded: *mut BYTE, pcbEncoded: *mut DWORD, ppszError: *mut LPCSTR, + ) -> BOOL; + pub fn CertStrToNameW( + dwCertEncodingType: DWORD, pszX500: LPCWSTR, dwStrType: DWORD, pvReserved: *mut c_void, + pbEncoded: *mut BYTE, pcbEncoded: *mut DWORD, ppszError: *mut LPCWSTR, + ) -> BOOL; + pub fn CertUnregisterPhysicalStore( + pvSystemStore: *const c_void, dwFlags: DWORD, pwszStoreName: LPCWSTR, + ) -> BOOL; + pub fn CertUnregisterSystemStore(pvSystemStore: *const c_void, dwFlags: DWORD) -> BOOL; + pub fn CertVerifyCRLRevocation( + dwCertEncodingType: DWORD, pCertId: PCERT_INFO, cCrlInfo: DWORD, rgpCrlInfo: *mut PCRL_INFO, + ) -> BOOL; + pub fn CertVerifyCRLTimeValidity(pTimeToVerify: LPFILETIME, pCrlInfo: PCRL_INFO) -> LONG; + pub fn CertVerifyCTLUsage( + dwEncodingType: DWORD, dwSubjectType: DWORD, pvSubject: *mut c_void, + pSubjectUsage: PCTL_USAGE, dwFlags: DWORD, pVerifyUsagePara: PCTL_VERIFY_USAGE_PARA, + pVerifyUsageStatus: PCTL_VERIFY_USAGE_STATUS, + ) -> BOOL; + pub fn CertVerifyCertificateChainPolicy( + pszPolicyOID: LPCSTR, pChainContext: PCCERT_CHAIN_CONTEXT, + pPolicyPara: PCERT_CHAIN_POLICY_PARA, pPolicyStatus: PCERT_CHAIN_POLICY_STATUS, + ) -> BOOL; + pub fn CertVerifyRevocation( + dwEncodingType: DWORD, dwRevType: DWORD, cContext: DWORD, rgpvContext: *mut PVOID, + dwFlags: DWORD, pRevPara: PCERT_REVOCATION_PARA, pRevStatus: PCERT_REVOCATION_STATUS, + ) -> BOOL; + pub fn CertVerifySubjectCertificateContext( + pSubject: PCCERT_CONTEXT, pIssuer: PCCERT_CONTEXT, pdwFlags: *mut DWORD, + ) -> BOOL; + pub fn CertVerifyTimeValidity(pTimeToVerify: LPFILETIME, pCertInfo: PCERT_INFO) -> LONG; + pub fn CertVerifyValidityNesting(pSubjectInfo: PCERT_INFO, pIssuerInfo: PCERT_INFO) -> BOOL; + pub fn CryptAcquireCertificatePrivateKey( + pCert: PCCERT_CONTEXT, dwFlags: DWORD, pvParameters: *mut c_void, + phCryptProvOrNCryptKey: *mut HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, pdwKeySpec: *mut DWORD, + pfCallerFreeProvOrNCryptKey: *mut BOOL, + ) -> BOOL; + pub fn CryptBinaryToStringA( + pbBinary: *const BYTE, cbBinary: DWORD, dwFlags: DWORD, pszString: LPSTR, + pcchString: *mut DWORD, + ) -> BOOL; + pub fn CryptBinaryToStringW( + pbBinary: *const BYTE, cbBinary: DWORD, dwFlags: DWORD, pszString: LPWSTR, + pcchString: *mut DWORD, + ) -> BOOL; + pub fn CryptCloseAsyncHandle(hAsync: HCRYPTASYNC) -> BOOL; + pub fn CryptCreateAsyncHandle(dwFlags: DWORD, phAsync: PHCRYPTASYNC) -> BOOL; + pub fn CryptCreateKeyIdentifierFromCSP( + dwCertEncodingType: DWORD, pszPubKeyOID: LPCSTR, pPubKeyStruc: *const PUBLICKEYSTRUC, + cbPubKeyStruc: DWORD, dwFlags: DWORD, pvReserved: *mut c_void, pbHash: *mut BYTE, + pcbHash: *mut DWORD, + ) -> BOOL; + pub fn CryptDecodeMessage( + dwMsgTypeFlags: DWORD, pDecryptPara: PCRYPT_DECRYPT_MESSAGE_PARA, + pVerifyPara: PCRYPT_VERIFY_MESSAGE_PARA, dwSignerIndex: DWORD, pbEncodedBlob: *const BYTE, + cbEncodedBlob: DWORD, dwPrevInnerContentType: DWORD, pdwMsgType: *mut DWORD, + pdwInnerContentType: *mut DWORD, pbDecoded: *mut BYTE, pcbDecoded: *mut DWORD, + ppXchgCert: *mut PCCERT_CONTEXT, ppSignerCert: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CryptDecodeObject( + dwCertEncodingType: DWORD, lpszStructType: LPCSTR, pbEncoded: *const BYTE, + cbEncoded: DWORD, dwFlags: DWORD, pvStructInfo: *mut c_void, pcbStructInfo: *mut DWORD, + ) -> BOOL; + pub fn CryptDecodeObjectEx( + dwCertEncodingType: DWORD, lpszStructType: LPCSTR, pbEncoded: *const BYTE, + cbEncoded: DWORD, dwFlags: DWORD, pDecodePara: PCRYPT_DECODE_PARA, + pvStructInfo: *mut c_void, pcbStructInfo: *mut DWORD, + ) -> BOOL; + pub fn CryptDecryptAndVerifyMessageSignature( + pDecryptPara: PCRYPT_DECRYPT_MESSAGE_PARA, pVerifyPara: PCRYPT_VERIFY_MESSAGE_PARA, + dwSignerIndex: DWORD, pbEncryptedBlob: *const BYTE, cbEncryptedBlob: DWORD, + pbDecrypted: *mut BYTE, pcbDecrypted: *mut DWORD, ppXchgCert: *mut PCCERT_CONTEXT, + ppSignerCert: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CryptDecryptMessage( + pDecryptPara: PCRYPT_DECRYPT_MESSAGE_PARA, pbEncryptedBlob: *const BYTE, + cbEncryptedBlob: DWORD, pbDecrypted: *mut BYTE, pcbDecrypted: *mut DWORD, + ppXchgCert: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CryptEncodeObject( + dwCertEncodingType: DWORD, lpszStructType: LPCSTR, pvStructInfo: *const c_void, + pbEncoded: *mut BYTE, pcbEncoded: *mut DWORD, + ) -> BOOL; + pub fn CryptEncodeObjectEx( + dwCertEncodingType: DWORD, lpszStructType: LPCSTR, pvStructInfo: *const c_void, + dwFlags: DWORD, pEncodePara: PCRYPT_ENCODE_PARA, pvEncoded: *mut c_void, + pcbEncoded: *mut DWORD, + ) -> BOOL; + pub fn CryptEncryptMessage( + pEncryptPara: PCRYPT_ENCRYPT_MESSAGE_PARA, cRecipientCert: DWORD, + rgpRecipientCert: *mut PCCERT_CONTEXT, pbToBeEncrypted: *const BYTE, + cbToBeEncrypted: DWORD, pbEncryptedBlob: *mut BYTE, pcbEncryptedBlob: *mut DWORD, + ) -> BOOL; + pub fn CryptEnumKeyIdentifierProperties( + pKeyIdentifier: *const CRYPT_HASH_BLOB, dwPropId: DWORD, dwFlags: DWORD, + pwszComputerName: LPCWSTR, pvReserved: *mut c_void, pvArg: *mut c_void, + pfnEnum: PFN_CRYPT_ENUM_KEYID_PROP, + ) -> BOOL; + pub fn CryptEnumOIDFunction( + dwEncodingType: DWORD, pszFuncName: LPCSTR, pszOID: LPCSTR, dwFlags: DWORD, + pvArg: *mut c_void, pfnEnumOIDFunc: PFN_CRYPT_ENUM_OID_FUNC, + ) -> BOOL; + pub fn CryptEnumOIDInfo( + dwGroupId: DWORD, dwFlags: DWORD, pvArg: *mut c_void, + pfnEnumOIDInfo: PFN_CRYPT_ENUM_OID_INFO, + ) -> BOOL; + pub fn CryptExportPKCS8( + hCryptProv: HCRYPTPROV, dwKeySpec: DWORD, pszPrivateKeyObjId: LPSTR, dwFlags: DWORD, + pvAuxInfo: *mut c_void, pbPrivateKeyBlob: *mut BYTE, pcbPrivateKeyBlob: *mut DWORD, + ) -> BOOL; + pub fn CryptExportPublicKeyInfo( + hCryptProvOrNCryptKey: HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, dwKeySpec: DWORD, + dwCertEncodingType: DWORD, pInfo: PCERT_PUBLIC_KEY_INFO, pcbInfo: *mut DWORD, + ) -> BOOL; + pub fn CryptExportPublicKeyInfoEx( + hCryptProvOrNCryptKey: HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, dwKeySpec: DWORD, + dwCertEncodingType: DWORD, pszPublicKeyObjId: LPSTR, dwFlags: DWORD, + pvAuxInfo: *mut c_void, pInfo: PCERT_PUBLIC_KEY_INFO, pcbInfo: *mut DWORD, + ) -> BOOL; + pub fn CryptExportPublicKeyInfoFromBCryptKeyHandle( + hBCryptKey: BCRYPT_KEY_HANDLE, dwCertEncodingType: DWORD, pszPublicKeyObjId: LPSTR, + dwFlags: DWORD, pvAuxInfo: *mut c_void, pInfo: PCERT_PUBLIC_KEY_INFO, pcbInfo: *mut DWORD, + ) -> BOOL; + pub fn CryptFindCertificateKeyProvInfo( + pCert: PCCERT_CONTEXT, dwFlags: DWORD, pvReserved: *mut c_void, + ) -> BOOL; + pub fn CryptFindLocalizedName(pwszCryptName: LPCWSTR) -> LPCWSTR; + pub fn CryptFindOIDInfo( + dwKeyType: DWORD, pvKey: *mut c_void, dwGroupId: DWORD, + ) -> PCCRYPT_OID_INFO; + pub fn CryptFormatObject( + dwCertEncodingType: DWORD, dwFormatType: DWORD, dwFormatStrType: DWORD, + pFormatStruct: *mut c_void, lpszStructType: LPCSTR, pbEncoded: *const BYTE, + cbEncoded: DWORD, pbFormat: *mut c_void, pcbFormat: *mut DWORD, + ) -> BOOL; + pub fn CryptFreeOIDFunctionAddress(hFuncAddr: HCRYPTOIDFUNCADDR, dwFlags: DWORD) -> BOOL; + pub fn CryptGetAsyncParam( + hAsync: HCRYPTASYNC, pszParamOid: LPSTR, ppvParam: *mut LPVOID, + ppfnFree: *mut PFN_CRYPT_ASYNC_PARAM_FREE_FUNC, + ) -> BOOL; + pub fn CryptGetDefaultOIDDllList( + hFuncSet: HCRYPTOIDFUNCSET, dwEncodingType: DWORD, pwszDllList: *mut WCHAR, + pcchDllList: *mut DWORD, + ) -> BOOL; + pub fn CryptGetDefaultOIDFunctionAddress( + hFuncSet: HCRYPTOIDFUNCSET, dwEncodingType: DWORD, pwszDll: LPCWSTR, dwFlags: DWORD, + ppvFuncAddr: *mut *mut c_void, phFuncAddr: *mut HCRYPTOIDFUNCADDR, + ) -> BOOL; + pub fn CryptGetKeyIdentifierProperty( + pKeyIdentifier: *const CRYPT_HASH_BLOB, dwPropId: DWORD, dwFlags: DWORD, + pwszComputerName: LPCWSTR, pvReserved: *mut c_void, pvData: *mut c_void, + pcbData: *mut DWORD, + ) -> BOOL; + pub fn CryptGetMessageCertificates( + dwMsgAndCertEncodingType: DWORD, hCryptProv: HCRYPTPROV_LEGACY, dwFlags: DWORD, + pbSignedBlob: *const BYTE, cbSignedBlob: DWORD, + ) -> HCERTSTORE; + pub fn CryptGetMessageSignerCount( + dwMsgEncodingType: DWORD, pbSignedBlob: *const BYTE, cbSignedBlob: DWORD, + ) -> LONG; + pub fn CryptGetOIDFunctionAddress( + hFuncSet: HCRYPTOIDFUNCSET, dwEncodingType: DWORD, pszOID: LPCSTR, dwFlags: DWORD, + ppvFuncAddr: *mut *mut c_void, phFuncAddr: *mut HCRYPTOIDFUNCADDR, + ) -> BOOL; + pub fn CryptGetOIDFunctionValue( + dwEncodingType: DWORD, pszFuncName: LPCSTR, pszOID: LPCSTR, pwszValueName: LPCWSTR, + pdwValueType: *mut DWORD, pbValueData: *mut BYTE, pcbValueData: *mut DWORD, + ) -> BOOL; + pub fn CryptHashCertificate( + hCryptProv: HCRYPTPROV_LEGACY, Algid: ALG_ID, dwFlags: DWORD, pbEncoded: *const BYTE, + cbEncoded: DWORD, pbComputedHash: *mut BYTE, pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptHashCertificate2( + pwszCNGHashAlgid: LPCWSTR, dwFlags: DWORD, pvReserved: *mut c_void, pbEncoded: *const BYTE, + cbEncoded: DWORD, pbComputedHash: *mut BYTE, pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptHashMessage( + pHashPara: PCRYPT_HASH_MESSAGE_PARA, fDetachedHash: BOOL, cToBeHashed: DWORD, + rgpbToBeHashed: *mut *const BYTE, rgcbToBeHashed: *mut DWORD, pbHashedBlob: *mut BYTE, + pcbHashedBlob: *mut DWORD, pbComputedHash: *mut BYTE, pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptHashPublicKeyInfo( + hCryptProv: HCRYPTPROV_LEGACY, Algid: ALG_ID, dwFlags: DWORD, dwCertEncodingType: DWORD, + pInfo: PCERT_PUBLIC_KEY_INFO, pbComputedHash: *mut BYTE, pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptHashToBeSigned( + hCryptProv: HCRYPTPROV_LEGACY, dwCertEncodingType: DWORD, pbEncoded: *const BYTE, + cbEncoded: DWORD, pbComputedHash: *mut BYTE, pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptImportPKCS8( + sPrivateKeyAndParams: CRYPT_PKCS8_IMPORT_PARAMS, dwFlags: DWORD, + phCryptProv: *mut HCRYPTPROV, pvAuxInfo: *mut c_void, + ) -> BOOL; + pub fn CryptImportPublicKeyInfo( + hCryptProv: HCRYPTPROV, dwCertEncodingType: DWORD, pInfo: PCERT_PUBLIC_KEY_INFO, + phKey: *mut HCRYPTKEY, + ) -> BOOL; + pub fn CryptImportPublicKeyInfoEx( + hCryptProv: HCRYPTPROV, dwCertEncodingType: DWORD, pInfo: PCERT_PUBLIC_KEY_INFO, + aiKeyAlg: ALG_ID, dwFlags: DWORD, pvAuxInfo: *mut c_void, phKey: *mut HCRYPTKEY, + ) -> BOOL; + pub fn CryptImportPublicKeyInfoEx2( + dwCertEncodingType: DWORD, pInfo: PCERT_PUBLIC_KEY_INFO, dwFlags: DWORD, + pvAuxInfo: *mut c_void, phKey: *mut BCRYPT_KEY_HANDLE, + ) -> BOOL; + pub fn CryptInitOIDFunctionSet(pszFuncName: LPCSTR, dwFlags: DWORD) -> HCRYPTOIDFUNCSET; + pub fn CryptInstallDefaultContext( + hCryptProv: HCRYPTPROV, dwDefaultType: DWORD, pvDefaultPara: *const c_void, dwFlags: DWORD, + pvReserved: *mut c_void, phDefaultContext: *mut HCRYPTDEFAULTCONTEXT, + ) -> BOOL; + pub fn CryptInstallOIDFunctionAddress( + hModule: HMODULE, dwEncodingType: DWORD, pszFuncName: LPCSTR, cFuncEntry: DWORD, + rgFuncEntry: *const CRYPT_OID_FUNC_ENTRY, dwFlags: DWORD, + ) -> BOOL; + // pub fn CryptLoadSip(); + pub fn CryptMemAlloc(cbSize: ULONG) -> LPVOID; + pub fn CryptMemFree(pv: LPVOID); + pub fn CryptMemRealloc(pv: LPVOID, cbSize: ULONG) -> LPVOID; + pub fn CryptMsgCalculateEncodedLength( + dwMsgEncodingType: DWORD, dwFlags: DWORD, dwMsgType: DWORD, pvMsgEncodeInfo: *const c_void, + pszInnerContentObjID: LPSTR, cbData: DWORD, + ) -> DWORD; + pub fn CryptMsgClose(hCryptMsg: HCRYPTMSG) -> BOOL; + pub fn CryptMsgControl( + hCryptMsg: HCRYPTMSG, dwFlags: DWORD, dwCtrlType: DWORD, pvCtrlPara: *const c_void, + ) -> BOOL; + pub fn CryptMsgCountersign( + hCryptMsg: HCRYPTMSG, dwIndex: DWORD, cCountersigners: DWORD, + rgCountersigners: PCMSG_SIGNER_ENCODE_INFO, + ) -> BOOL; + pub fn CryptMsgCountersignEncoded( + dwEncodingType: DWORD, pbSignerInfo: PBYTE, cbSignerInfo: DWORD, cCountersigners: DWORD, + rgCountersigners: PCMSG_SIGNER_ENCODE_INFO, pbCountersignature: PBYTE, + pcbCountersignature: PDWORD, + ) -> BOOL; + pub fn CryptMsgDuplicate(hCryptMsg: HCRYPTMSG) -> HCRYPTMSG; + pub fn CryptMsgEncodeAndSignCTL( + dwMsgEncodingType: DWORD, pCtlInfo: PCTL_INFO, pSignInfo: PCMSG_SIGNED_ENCODE_INFO, + dwFlags: DWORD, pbEncoded: *mut BYTE, pcbEncoded: *mut DWORD, + ) -> BOOL; + pub fn CryptMsgGetAndVerifySigner( + hCryptMsg: HCRYPTMSG, cSignerStore: DWORD, rghSignerStore: *mut HCERTSTORE, dwFlags: DWORD, + ppSigner: *mut PCCERT_CONTEXT, pdwSignerIndex: *mut DWORD, + ) -> BOOL; + pub fn CryptMsgGetParam( + hCryptMsg: HCRYPTMSG, dwParamType: DWORD, dwIndex: DWORD, pvData: *mut c_void, + pcbData: *mut DWORD, + ) -> BOOL; + pub fn CryptMsgOpenToDecode( + dwMsgEncodingType: DWORD, dwFlags: DWORD, dwMsgType: DWORD, hCryptProv: HCRYPTPROV_LEGACY, + pRecipientInfo: PCERT_INFO, pStreamInfo: PCMSG_STREAM_INFO, + ) -> HCRYPTMSG; + pub fn CryptMsgOpenToEncode( + dwMsgEncodingType: DWORD, dwFlags: DWORD, dwMsgType: DWORD, pvMsgEncodeInfo: *mut c_void, + pszInnerContentObjID: LPSTR, pStreamInfo: PCMSG_STREAM_INFO, + ) -> HCRYPTMSG; + pub fn CryptMsgSignCTL( + dwMsgEncodingType: DWORD, pbCtlContent: *mut BYTE, cbCtlContent: DWORD, + pSignInfo: PCMSG_SIGNED_ENCODE_INFO, dwFlags: DWORD, pbEncoded: *mut BYTE, + pcbEncoded: *mut DWORD, + ) -> BOOL; + pub fn CryptMsgUpdate( + hCryptMsg: HCRYPTMSG, pbData: *const BYTE, cbData: DWORD, fFinal: BOOL, + ) -> BOOL; + pub fn CryptMsgVerifyCountersignatureEncoded( + hCryptProv: HCRYPTPROV_LEGACY, dwEncodingType: DWORD, pbSignerInfo: PBYTE, + cbSignerInfo: DWORD, pbSignerInfoCountersignature: PBYTE, + cbSignerInfoCountersignature: DWORD, pciCountersigner: PCERT_INFO, + ) -> BOOL; + pub fn CryptMsgVerifyCountersignatureEncodedEx( + hCryptProv: HCRYPTPROV_LEGACY, dwEncodingType: DWORD, pbSignerInfo: PBYTE, + cbSignerInfo: DWORD, pbSignerInfoCountersignature: PBYTE, + cbSignerInfoCountersignature: DWORD, dwSignerType: DWORD, pvSigner: *mut c_void, + dwFlags: DWORD, pvExtra: *mut c_void, + ) -> BOOL; + pub fn CryptProtectData( + pDataIn: *mut DATA_BLOB, szDataDescr: LPCWSTR, pOptionalEntropy: *mut DATA_BLOB, + pvReserved: PVOID, pPromptStruct: *mut CRYPTPROTECT_PROMPTSTRUCT, dwFlags: DWORD, + pDataOut: *mut DATA_BLOB, + ) -> BOOL; + pub fn CryptProtectMemory(pDataIn: LPVOID, cbDataIn: DWORD, dwFlags: DWORD) -> BOOL; + pub fn CryptQueryObject( + dwObjectType: DWORD, pvObject: *const c_void, dwExpectedContentTypeFlags: DWORD, + dwExpectedFormatTypeFlags: DWORD, dwFlags: DWORD, pdwMsgAndCertEncodingType: *mut DWORD, + pdwContentType: *mut DWORD, pdwFormatType: *mut DWORD, phCertStore: *mut HCERTSTORE, + phMsg: *mut HCRYPTMSG, ppvContext: *mut *const c_void, + ) -> BOOL; + pub fn CryptRegisterDefaultOIDFunction( + dwEncodingType: DWORD, pszFuncName: LPCSTR, dwIndex: DWORD, pwszDll: LPCWSTR, + ) -> BOOL; + pub fn CryptRegisterOIDFunction( + dwEncodingType: DWORD, pszFuncName: LPCSTR, pszOID: LPCSTR, pwszDll: LPCWSTR, + pszOverrideFuncName: LPCSTR, + ) -> BOOL; + pub fn CryptRegisterOIDInfo(pInfo: PCCRYPT_OID_INFO, dwFlags: DWORD) -> BOOL; + pub fn CryptRetrieveTimeStamp( + wszUrl: LPCWSTR, dwRetrievalFlags: DWORD, dwTimeout: DWORD, pszHashId: LPCSTR, + pPara: *const CRYPT_TIMESTAMP_PARA, pbData: *const BYTE, cbData: DWORD, + ppTsContext: *mut PCRYPT_TIMESTAMP_CONTEXT, ppTsSigner: *mut PCCERT_CONTEXT, + phStore: *mut HCERTSTORE, + ) -> BOOL; + pub fn CryptSIPAddProvider(psNewProv: *mut SIP_ADD_NEWPROVIDER) -> BOOL; + pub fn CryptSIPCreateIndirectData( + pSubjectInfo: *mut SIP_SUBJECTINFO, pcbIndirectData: *mut DWORD, + pIndirectData: *mut SIP_INDIRECT_DATA, + ) -> BOOL; + pub fn CryptSIPGetCaps(pSubjInfo: *mut SIP_SUBJECTINFO, pCaps: *mut SIP_CAP_SET) -> BOOL; + pub fn CryptSIPGetSealedDigest( + pSubjectInfo: *mut SIP_SUBJECTINFO, pSig: *const BYTE, dwSig: DWORD, pbDigest: *mut BYTE, + pcbDigest: *mut DWORD, + ) -> BOOL; + pub fn CryptSIPGetSignedDataMsg( + pSubjectInfo: *mut SIP_SUBJECTINFO, pdwEncodingType: *mut DWORD, dwIndex: DWORD, + pcbSignedDataMsg: *mut DWORD, pbSignedDataMsg: *mut BYTE, + ) -> BOOL; + pub fn CryptSIPLoad( + pgSubject: *const GUID, dwFlags: DWORD, pSipDispatch: *mut SIP_DISPATCH_INFO, + ) -> BOOL; + pub fn CryptSIPPutSignedDataMsg( + pSubjectInfo: *mut SIP_SUBJECTINFO, dwEncodingType: DWORD, pdwIndex: *mut DWORD, + cbSignedDataMsg: DWORD, pbSignedDataMsg: *mut BYTE, + ) -> BOOL; + pub fn CryptSIPRemoveProvider(pgProv: *mut GUID) -> BOOL; + pub fn CryptSIPRemoveSignedDataMsg(pSubjectInfo: *mut SIP_SUBJECTINFO, dwIndex: DWORD) -> BOOL; + pub fn CryptSIPRetrieveSubjectGuid( + FileName: LPCWSTR, hFileIn: HANDLE, pgSubject: *mut GUID, + ) -> BOOL; + pub fn CryptSIPRetrieveSubjectGuidForCatalogFile( + FileName: LPCWSTR, hFileIn: HANDLE, pgSubject: *mut GUID, + ) -> BOOL; + pub fn CryptSIPVerifyIndirectData( + pSubjectInfo: *mut SIP_SUBJECTINFO, pIndirectData: *mut SIP_INDIRECT_DATA, + ) -> BOOL; + pub fn CryptSetAsyncParam( + hAsync: HCRYPTASYNC, pszParamOid: LPSTR, pvParam: LPVOID, + pfnFree: PFN_CRYPT_ASYNC_PARAM_FREE_FUNC, + ) -> BOOL; + pub fn CryptSetKeyIdentifierProperty( + pKeyIdentifier: *const CRYPT_HASH_BLOB, dwPropId: DWORD, dwFlags: DWORD, + pwszComputerName: LPCWSTR, pvReserved: *mut c_void, pvData: *const c_void, + ) -> BOOL; + pub fn CryptSetOIDFunctionValue( + dwEncodingType: DWORD, pszFuncName: LPCSTR, pszOID: LPCSTR, pwszValueName: LPCWSTR, + dwValueType: DWORD, pbValueData: *const BYTE, cbValueData: DWORD, + ) -> BOOL; + pub fn CryptSignAndEncodeCertificate( + hCryptProvOrNCryptKey: HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, dwKeySpec: DWORD, + dwCertEncodingType: DWORD, lpszStructType: LPCSTR, pvStructInfo: *const c_void, + pSignatureAlgorithm: PCRYPT_ALGORITHM_IDENTIFIER, pvHashAuxInfo: *const c_void, + pbEncoded: *mut BYTE, pcbEncoded: *mut DWORD, + ) -> BOOL; + pub fn CryptSignAndEncryptMessage( + pSignPara: PCRYPT_SIGN_MESSAGE_PARA, pEncryptPara: PCRYPT_ENCRYPT_MESSAGE_PARA, + cRecipientCert: DWORD, rgpRecipientCert: *mut PCCERT_CONTEXT, + pbToBeSignedAndEncrypted: *const BYTE, cbToBeSignedAndEncrypted: DWORD, + pbSignedAndEncryptedBlob: *mut BYTE, pcbSignedAndEncryptedBlob: *mut DWORD, + ) -> BOOL; + pub fn CryptSignCertificate( + hCryptProvOrNCryptKey: HCRYPTPROV_OR_NCRYPT_KEY_HANDLE, dwKeySpec: DWORD, + dwCertEncodingType: DWORD, pbEncodedToBeSigned: *const BYTE, cbEncodedToBeSigned: DWORD, + pSignatureAlgorithm: PCRYPT_ALGORITHM_IDENTIFIER, pvHashAuxInfo: *const c_void, + pbSignature: *mut BYTE, pcbSignature: *mut DWORD, + ) -> BOOL; + pub fn CryptSignMessage( + pSignPara: PCRYPT_SIGN_MESSAGE_PARA, fDetachedSignature: BOOL, cToBeSigned: DWORD, + rgpbToBeSigned: *mut *const BYTE, rgcbToBeSigned: *mut DWORD, pbSignedBlob: *mut BYTE, + pcbSignedBlob: *mut DWORD, + ) -> BOOL; + pub fn CryptSignMessageWithKey( + pSignPara: PCRYPT_KEY_SIGN_MESSAGE_PARA, pbToBeSigned: *const BYTE, cbToBeSigned: DWORD, + pbSignedBlob: *mut BYTE, pcbSignedBlob: *mut DWORD, + ) -> BOOL; + pub fn CryptStringToBinaryA( + pszString: LPCSTR, cchString: DWORD, dwFlags: DWORD, pbBinary: *mut BYTE, + pcbBinary: *mut DWORD, pdwSkip: *mut DWORD, pdwFlags: *mut DWORD, + ) -> BOOL; + pub fn CryptStringToBinaryW( + pszString: LPCWSTR, cchString: DWORD, dwFlags: DWORD, pbBinary: *mut BYTE, + pcbBinary: *mut DWORD, pdwSkip: *mut DWORD, pdwFlags: *mut DWORD, + ) -> BOOL; + pub fn CryptUninstallDefaultContext( + hDefaultContext: HCRYPTDEFAULTCONTEXT, dwFlags: DWORD, pvReserved: *mut c_void, + ) -> BOOL; + pub fn CryptUnprotectData( + pDataIn: *mut DATA_BLOB, ppszDataDescr: *mut LPWSTR, pOptionalEntropy: *mut DATA_BLOB, + pvReserved: PVOID, pPromptStruct: *mut CRYPTPROTECT_PROMPTSTRUCT, dwFlags: DWORD, + pDataOut: *mut DATA_BLOB, + ) -> BOOL; + pub fn CryptUnprotectMemory(pDataIn: LPVOID, cbDataIn: DWORD, dwFlags: DWORD) -> BOOL; + pub fn CryptUnregisterDefaultOIDFunction( + dwEncodingType: DWORD, pszFuncName: LPCSTR, pwszDll: LPCWSTR, + ) -> BOOL; + pub fn CryptUnregisterOIDFunction( + dwEncodingType: DWORD, pszFuncName: LPCSTR, pszOID: LPCSTR, + ) -> BOOL; + pub fn CryptUnregisterOIDInfo(pInfo: PCCRYPT_OID_INFO) -> BOOL; + pub fn CryptUpdateProtectedState( + pOldSid: PSID, pwszOldPassword: LPCWSTR, dwFlags: DWORD, pdwSuccessCount: *mut DWORD, + pdwFailureCount: *mut DWORD, + ) -> BOOL; + pub fn CryptVerifyCertificateSignature( + hCryptProv: HCRYPTPROV_LEGACY, dwCertEncodingType: DWORD, pbEncoded: *const BYTE, + cbEncoded: DWORD, pPublicKey: PCERT_PUBLIC_KEY_INFO, + ) -> BOOL; + pub fn CryptVerifyCertificateSignatureEx( + hCryptProv: HCRYPTPROV_LEGACY, dwCertEncodingType: DWORD, dwSubjectType: DWORD, + pvSubject: *mut c_void, dwIssuerType: DWORD, pvIssuer: *mut c_void, dwFlags: DWORD, + pvExtra: *mut c_void, + ) -> BOOL; + pub fn CryptVerifyDetachedMessageHash( + pHashPara: PCRYPT_HASH_MESSAGE_PARA, pbDetachedHashBlob: *mut BYTE, + cbDetachedHashBlob: DWORD, cToBeHashed: DWORD, rgpbToBeHashed: *mut *const BYTE, + rgcbToBeHashed: *mut DWORD, pbComputedHash: *mut BYTE, pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptVerifyDetachedMessageSignature( + pVerifyPara: PCRYPT_VERIFY_MESSAGE_PARA, dwSignerIndex: DWORD, + pbDetachedSignBlob: *const BYTE, cbDetachedSignBlob: DWORD, cToBeSigned: DWORD, + rgpbToBeSigned: *mut *const BYTE, rgcbToBeSigned: *mut DWORD, + ppSignerCert: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CryptVerifyMessageHash( + pHashPara: PCRYPT_HASH_MESSAGE_PARA, pbHashedBlob: *mut BYTE, cbHashedBlob: DWORD, + pbToBeHashed: *mut BYTE, pcbToBeHashed: *mut DWORD, pbComputedHash: *mut BYTE, + pcbComputedHash: *mut DWORD, + ) -> BOOL; + pub fn CryptVerifyMessageSignature( + pVerifyPara: PCRYPT_VERIFY_MESSAGE_PARA, dwSignerIndex: DWORD, pbSignedBlob: *const BYTE, + cbSignedBlob: DWORD, pbDecoded: *mut BYTE, pcbDecoded: *mut DWORD, + ppSignerCert: *mut PCCERT_CONTEXT, + ) -> BOOL; + pub fn CryptVerifyMessageSignatureWithKey( + pVerifyPara: PCRYPT_KEY_VERIFY_MESSAGE_PARA, pPublicKeyInfo: PCERT_PUBLIC_KEY_INFO, + pbSignedBlob: *const BYTE, cbSignedBlob: DWORD, pbDecoded: *mut BYTE, + pcbDecoded: *mut DWORD, + ) -> BOOL; + pub fn CryptVerifyTimeStampSignature( + pbTSContentInfo: *const BYTE, cbTSContentInfo: DWORD, pbData: *const BYTE, cbData: DWORD, + hAdditionalStore: HCERTSTORE, ppTsContext: *mut PCRYPT_TIMESTAMP_CONTEXT, + ppTsSigner: *mut PCCERT_CONTEXT, phStore: *mut HCERTSTORE, + ) -> BOOL; + // pub fn DbgInitOSS(); + pub fn PFXExportCertStore( + hStore: HCERTSTORE, pPFX: *mut CRYPT_DATA_BLOB, szPassword: LPCWSTR, dwFlags: DWORD, + ) -> BOOL; + // pub fn PFXExportCertStore2(); + pub fn PFXExportCertStoreEx( + hStore: HCERTSTORE, pPFX: *mut CRYPT_DATA_BLOB, szPassword: LPCWSTR, pvPara: *mut c_void, + dwFlags: DWORD, + ) -> BOOL; + pub fn PFXImportCertStore( + pPFX: *mut CRYPT_DATA_BLOB, szPassword: LPCWSTR, dwFlags: DWORD, + ) -> HCERTSTORE; + pub fn PFXIsPFXBlob(pPFX: *mut CRYPT_DATA_BLOB) -> BOOL; + pub fn PFXVerifyPassword( + pPFX: *mut CRYPT_DATA_BLOB, szPassword: LPCWSTR, dwFlags: DWORD, + ) -> BOOL; +} diff --git a/crypto-hash-0.3.0/.cargo-checksum.json b/crypto-hash-0.3.0/.cargo-checksum.json new file mode 100644 index 000000000..100654e14 --- /dev/null +++ b/crypto-hash-0.3.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"34903878eec1694faf53cae8473a088df333181de421d4d3d48061d6559fe602"} \ No newline at end of file diff --git a/crypto-hash-0.3.0/CONTRIBUTING.md b/crypto-hash-0.3.0/CONTRIBUTING.md new file mode 100644 index 000000000..1b33a9ec1 --- /dev/null +++ b/crypto-hash-0.3.0/CONTRIBUTING.md @@ -0,0 +1,77 @@ +# Contributing to `crypto-hash` + +`crypto-hash` is a part of the Rust ecosystem. As such, all contributions to this project follow the +[Rust language's code of conduct](https://www.rust-lang.org/conduct.html) where appropriate. + +This project is hosted at [GitHub](https://github.com/malept/crypto-hash). Both pull requests and +issues of many different kinds are accepted. + +## Filing Issues + +Issues include bugs, questions, feedback, and feature requests. Before you file a new issue, please +make sure that your issue has not already been filed by someone else. + +### Filing Bugs + +When filing a bug, please include the following information: + +* Operating system and version. If on Linux, please also include the distribution name. +* System architecture. Examples include: x86-64, x86, and ARMv7. +* Rust version that compiled `crypto-hash`. +* The version (and/or git revision) of `crypto-hash`. +* A detailed list of steps to reproduce the bug. A minimal testcase would be very helpful, + if possible. +* If there any any error messages in the console, copying them in the bug summary will be + very helpful. + +## Adding a new implementation + +If you are requesting or adding a new library source for hash algorithms, please make sure that it +supports all of the existing algorithms. For example, while the creator of this project supports the +efforts of the team writing LibreSSL, it does not support the MD5 algorithm. + +## Adding a new hash algorithm + +If you are requesting or adding a wrapper for a new hash algorithm, please make sure that it is +available in all of the supported implementations listed in the README. + +## Filing Pull Requests + +Here are some things to keep in mind as you file a pull request to fix a bug, add a new feature, +etc.: + +* Travis CI (for Linux and OS X) and AppVeyor (for Windows) are used to make sure that the project + builds as expected on the supported platforms, using the current stable and beta versions of Rust. + Make sure the testsuite passes locally by running `cargo test`. +* Unless it's impractical, please write tests for your changes. This will help spot regressions + much easier. +* If your PR changes the behavior of an existing feature, or adds a new feature, please add/edit + the `rustdoc` inline documentation. +* Please ensure that your changes follow the [rustfmt](https://github.com/rust-lang-nursery/rustfmt) + coding standard, and do not produce any warnings when running the + [clippy](https://github.com/Manishearth/rust-clippy) linter. +* If you are contributing a nontrivial change, please add an entry to `NEWS.md`. The format is + similar to the one described at [Keep a Changelog](http://keepachangelog.com/). +* Please make sure your commits are rebased onto the latest commit in the master branch, and that + you limit/squash the number of commits created to a "feature"-level. For instance: + +bad: + +``` +commit 1: add foo algorithm +commit 2: run rustfmt +commit 3: add test +commit 4: add docs +commit 5: add bar +commit 6: add test + docs +``` + +good: + +``` +commit 1: add foo algorithm +commit 2: add bar +``` + +If you are continuing the work of another person's PR and need to rebase/squash, please retain the +attribution of the original author(s) and continue the work in subsequent commits. diff --git a/crypto-hash-0.3.0/Cargo.toml b/crypto-hash-0.3.0/Cargo.toml new file mode 100644 index 000000000..cb9cf23f2 --- /dev/null +++ b/crypto-hash-0.3.0/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "crypto-hash" +version = "0.3.0" +authors = ["Mark Lee"] +description = "A wrapper for OS-level cryptographic hash functions" +documentation = "https://docs.rs/crypto-hash" +repository = "https://github.com/malept/crypto-hash" +readme = "README.md" +keywords = ["crypto", "hash", "digest"] +license = "MIT" +exclude = [ + ".*.yml", + "ci/*" +] + +[badges] +travis-ci = { repository = "malept/crypto-hash" } +appveyor = { repository = "malept/crypto-hash" } + +[dependencies] +hex = "0.2" + +[target.'cfg(target_os = "macos")'.dependencies] +commoncrypto = "0.2" + +[target.'cfg(target_os = "windows")'.dependencies] +advapi32-sys = "0.2" +winapi = "0.2" + +[target.'cfg(not(any(target_os = "windows", target_os = "macos")))'.dependencies] +openssl = "0.9" diff --git a/crypto-hash-0.3.0/LICENSE b/crypto-hash-0.3.0/LICENSE new file mode 100644 index 000000000..e3eb5500c --- /dev/null +++ b/crypto-hash-0.3.0/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015, 2016 Mark Lee + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/crypto-hash-0.3.0/Makefile b/crypto-hash-0.3.0/Makefile new file mode 100644 index 000000000..c675b5ee3 --- /dev/null +++ b/crypto-hash-0.3.0/Makefile @@ -0,0 +1,29 @@ +CARGO ?= cargo +CARGO_BUILD_TEST = $(CARGO) test --no-run +KCOV ?= kcov +TEST_APP = debug/crypto_hash-* +WIN_TARGET = x86_64-pc-windows-gnu + +build-test: + $(CARGO_BUILD_TEST) + +check-i686: + PKG_CONFIG_LIBDIR=/usr/lib/i386-linux-gnu/pkgconfig \ + PKG_CONFIG_ALLOW_CROSS=1 \ + $(CARGO) test --target i686-unknown-linux-gnu --verbose + +check-wine64: + $(CARGO_BUILD_TEST) --target $(WIN_TARGET) + WINEPREFIX=$(HOME)/.local/share/wineprefixes/wine64 wine64 target/$(WIN_TARGET)/$(TEST_APP) + +cov: build-test + $(KCOV) --exclude-pattern=/.multirust,test.rs target/cov target/$(TEST_APP) + +debug: build-test + rust-gdb target/$(TEST_APP) + +fmt: + $(CARGO) fmt + +lint: + $(CARGO) clippy --features=lint -- -Wclippy-pedantic diff --git a/crypto-hash-0.3.0/NEWS.md b/crypto-hash-0.3.0/NEWS.md new file mode 100644 index 000000000..50c808f18 --- /dev/null +++ b/crypto-hash-0.3.0/NEWS.md @@ -0,0 +1,49 @@ +# Changes by Version + +## Unreleased + +## [0.3.0] - 2017-06-18 + +### Changed + +* Upgrade to `commoncrypto` 0.2.x +* Function signatures for `digest` and `hex_digest` changed to use `&[u8]`, per Clippy + +## [0.2.1] - 2016-12-12 + +### Changed + +* Move CommonCrypto implementation to its own crate + +## [0.2.0] - 2016-11-06 + +### Added + +* SHA-1 algorithm + +### Changed + +* Upgrade rust-openssl to 0.9 + +## [0.1.0] - 2016-06-26 + +This release signifies the minimum amount of algorithms and implementations necessary for +[HTTP digest authentication](https://tools.ietf.org/html/rfc7616). + +### Added + +Algorithms: + +* MD5 +* SHA256 +* SHA512 + +Implementations: + +* CommonCrypto (OS X) +* CryptoAPI (Windows) +* OpenSSL (Linux/BSD/etc.) + +[0.2.1]: https://github.com/malept/crypto-hash/compare/v0.2.0...v0.2.1 +[0.2.0]: https://github.com/malept/crypto-hash/compare/v0.1.0...v0.2.0 +[0.1.0]: https://github.com/malept/crypto-hash/releases/tag/v0.1.0 diff --git a/crypto-hash-0.3.0/README.md b/crypto-hash-0.3.0/README.md new file mode 100644 index 000000000..64ac37532 --- /dev/null +++ b/crypto-hash-0.3.0/README.md @@ -0,0 +1,54 @@ +# `crypto-hash` + +[![Linux/OS X Status](https://travis-ci.org/malept/crypto-hash.svg?branch=master)](https://travis-ci.org/malept/crypto-hash) +[![Windows status](https://ci.appveyor.com/api/projects/status/xwc9nb4633b5n67r?svg=true)](https://ci.appveyor.com/project/malept/crypto-hash) +[![Crates.io](https://img.shields.io/crates/v/crypto-hash.svg?maxAge=2592000)](https://crates.io/crates/crypto-hash) + +`crypto-hash` is a Rust wrapper around OS-level implementations of cryptographic hash functions. + +The purpose of this crate is to provide access to hash algorithms with as few dependencies as +possible. This means that when possible, the library uses the hashing functions that are provided by +the given operating system's bundled cryptographic libraries. + +## Supported Implementations + +By operating system: + +* Windows: CryptoAPI +* OS X: [CommonCrypto](https://crates.io/crates/commoncrypto) +* Linux/BSD/etc.: [OpenSSL](https://crates.io/crates/openssl) + +## Supported Algorithms + +* MD5 +* SHA1 +* SHA256 +* SHA512 + +## Usage + +Add `crypto-hash` to your project's `Cargo.toml`. For more details, consult the +[Cargo guide](http://doc.crates.io/guide.html#adding-dependencies). + +Example: + +```rust +use crypto_hash::{Algorithm, hex_digest}; + +let digest = hex_digest(Algorithm::SHA256, b"crypto-hash".to_vec()); +``` + +For more examples, consult the [documentation](https://malept.github.io/crypto-hash/). + +## [Release Notes](https://github.com/malept/crypto-hash/blob/master/NEWS.md) + +## [Contributing](https://github.com/malept/crypto-hash/blob/master/CONTRIBUTING.md) + +## Acknowledgements + +This crate was inspired by [rust-native-tls](https://github.com/sfackler/rust-native-tls) and +[crypto-bench](https://github.com/briansmith/crypto-bench). + +## Legal + +`crypto-hash` is copyrighted under the terms of the MIT license. See LICENSE for details. diff --git a/crypto-hash-0.3.0/src/imp/commoncrypto.rs b/crypto-hash-0.3.0/src/imp/commoncrypto.rs new file mode 100644 index 000000000..310dc8018 --- /dev/null +++ b/crypto-hash-0.3.0/src/imp/commoncrypto.rs @@ -0,0 +1,81 @@ +// Copyright (c) 2016 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//! A cryptographic hash generator dependent upon OSX's `CommonCrypto`. + +use commoncrypto::hash; +use std::io; +use super::Algorithm; + +/// Generator of digests using a cryptographic hash function. +/// +/// # Examples +/// +/// ```rust +/// use crypto_hash::{Algorithm, Hasher}; +/// use std::io::Write; +/// +/// let mut hasher = Hasher::new(Algorithm::SHA256); +/// hasher.write_all(b"crypto"); +/// hasher.write_all(b"-"); +/// hasher.write_all(b"hash"); +/// let result = hasher.finish(); +/// let expected = +/// b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'" +/// .to_vec(); +/// assert_eq!(expected, result) +/// ``` +#[derive(Debug)] +pub struct Hasher(hash::Hasher); + +impl Hasher { + /// Create a new `Hasher` for the given `Algorithm`. + pub fn new(algorithm: Algorithm) -> Hasher { + let cc_algorithm = match algorithm { + Algorithm::MD5 => hash::CCDigestAlgorithm::kCCDigestMD5, + Algorithm::SHA1 => hash::CCDigestAlgorithm::kCCDigestSHA1, + Algorithm::SHA256 => hash::CCDigestAlgorithm::kCCDigestSHA256, + Algorithm::SHA512 => hash::CCDigestAlgorithm::kCCDigestSHA512, + }; + + Hasher(hash::Hasher::new(cc_algorithm)) + } + + /// Generate a digest from the data written to the `Hasher`. + pub fn finish(&mut self) -> Vec { + let Hasher(ref mut hasher) = *self; + match hasher.finish() { + Ok(digest) => digest, + Err(error) => panic!("CommonCrypto error: {}", error), + } + } +} + +impl io::Write for Hasher { + fn write(&mut self, buf: &[u8]) -> io::Result { + let Hasher(ref mut hasher) = *self; + hasher.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + let Hasher(ref mut hasher) = *self; + hasher.flush() + } +} diff --git a/crypto-hash-0.3.0/src/imp/cryptoapi.rs b/crypto-hash-0.3.0/src/imp/cryptoapi.rs new file mode 100644 index 000000000..bb693186a --- /dev/null +++ b/crypto-hash-0.3.0/src/imp/cryptoapi.rs @@ -0,0 +1,154 @@ +// Copyright (c) 2016 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//! A cryptographic hash generator dependent upon Windows's `CryptoAPI`. +//! +//! Originally based on: +//! https://github.com/rust-lang/cargo/blob/0.10.0/src/cargo/util/sha256.rs +//! which is copyright (c) 2014 The Rust Project Developers under the MIT license. + +use advapi32::{CryptAcquireContextW, CryptCreateHash, CryptDestroyHash, CryptGetHashParam, + CryptHashData, CryptReleaseContext}; +use std::io; +use std::ptr; +use super::Algorithm; +use winapi::{CALG_MD5, CALG_SHA1, CALG_SHA_256, CALG_SHA_512, CRYPT_SILENT, CRYPT_VERIFYCONTEXT, + DWORD, HCRYPTHASH, HCRYPTPROV, HP_HASHVAL, PROV_RSA_AES}; + +macro_rules! call { + ($e: expr) => ({ + if $e == 0 { + panic!("failed {}: {}", stringify!($e), io::Error::last_os_error()) + } + }) +} + +macro_rules! finish_algorithm { + ($func_name: ident, $size: ident) => { + fn $func_name(&mut self) -> Vec { + let mut len = $size as u32; + let mut hash = [0u8; $size]; + call!(unsafe { + CryptGetHashParam(self.hcrypthash, HP_HASHVAL, hash.as_mut_ptr(), &mut len, 0) + }); + assert_eq!(len as usize, hash.len()); + hash.to_vec() + } + } +} + +const MD5_LENGTH: usize = 16; +const SHA1_LENGTH: usize = 20; +const SHA256_LENGTH: usize = 32; +const SHA512_LENGTH: usize = 64; + +/// Generator of digests using a cryptographic hash function. +/// +/// # Examples +/// +/// ```rust +/// use crypto_hash::{Algorithm, Hasher}; +/// use std::io::Write; +/// +/// let mut hasher = Hasher::new(Algorithm::SHA256); +/// hasher.write_all(b"crypto"); +/// hasher.write_all(b"-"); +/// hasher.write_all(b"hash"); +/// let result = hasher.finish(); +/// let expected = +/// b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'" +/// .to_vec(); +/// assert_eq!(expected, result) +/// ``` +pub struct Hasher { + algorithm: Algorithm, + hcryptprov: HCRYPTPROV, + hcrypthash: HCRYPTHASH, +} + +impl Hasher { + /// Create a new `Hasher` for the given `Algorithm`. + pub fn new(algorithm: Algorithm) -> Hasher { + let mut hcp = 0; + call!(unsafe { + CryptAcquireContextW(&mut hcp, + ptr::null(), + ptr::null(), + PROV_RSA_AES, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT) + }); + + let hash_type = match algorithm { + Algorithm::MD5 => CALG_MD5, + Algorithm::SHA1 => CALG_SHA1, + Algorithm::SHA256 => CALG_SHA_256, + Algorithm::SHA512 => CALG_SHA_512, + }; + + let mut ret = Hasher { + algorithm: algorithm, + hcryptprov: hcp, + hcrypthash: 0, + }; + + call!(unsafe { CryptCreateHash(ret.hcryptprov, hash_type, 0, 0, &mut ret.hcrypthash) }); + ret + } + + /// Generate a digest from the data written to the `Hasher`. + pub fn finish(&mut self) -> Vec { + match self.algorithm { + Algorithm::MD5 => self.finish_md5(), + Algorithm::SHA1 => self.finish_sha1(), + Algorithm::SHA256 => self.finish_sha256(), + Algorithm::SHA512 => self.finish_sha512(), + } + } + + finish_algorithm!(finish_md5, MD5_LENGTH); + finish_algorithm!(finish_sha1, SHA1_LENGTH); + finish_algorithm!(finish_sha256, SHA256_LENGTH); + finish_algorithm!(finish_sha512, SHA512_LENGTH); +} + +impl io::Write for Hasher { + fn write(&mut self, buf: &[u8]) -> io::Result { + call!(unsafe { + CryptHashData(self.hcrypthash, + buf.as_ptr() as *mut _, + buf.len() as DWORD, + 0) + }); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Drop for Hasher { + fn drop(&mut self) { + if self.hcrypthash != 0 { + call!(unsafe { CryptDestroyHash(self.hcrypthash) }); + } + call!(unsafe { CryptReleaseContext(self.hcryptprov, 0) }); + } +} diff --git a/crypto-hash-0.3.0/src/imp/openssl.rs b/crypto-hash-0.3.0/src/imp/openssl.rs new file mode 100644 index 000000000..ba573c4c9 --- /dev/null +++ b/crypto-hash-0.3.0/src/imp/openssl.rs @@ -0,0 +1,85 @@ +// Copyright (c) 2015, 2016 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//! A cryptographic hash digest generator dependent upon `OpenSSL`. + +#![warn(missing_docs)] + +use openssl::hash; +use std::io; +use super::Algorithm; + +/// Generator of digests using a cryptographic hash function. +/// +/// # Examples +/// +/// ```rust +/// use crypto_hash::{Algorithm, Hasher}; +/// use std::io::Write; +/// +/// let mut hasher = Hasher::new(Algorithm::SHA256); +/// hasher.write_all(b"crypto"); +/// hasher.write_all(b"-"); +/// hasher.write_all(b"hash"); +/// let result = hasher.finish(); +/// let expected = +/// b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'" +/// .to_vec(); +/// assert_eq!(expected, result) +/// ``` +pub struct Hasher(hash::Hasher); + +impl Hasher { + /// Create a new `Hasher` for the given `Algorithm`. + pub fn new(algorithm: Algorithm) -> Hasher { + let hash_type = match algorithm { + Algorithm::MD5 => hash::MessageDigest::md5(), + Algorithm::SHA1 => hash::MessageDigest::sha1(), + Algorithm::SHA256 => hash::MessageDigest::sha256(), + Algorithm::SHA512 => hash::MessageDigest::sha512(), + }; + + match hash::Hasher::new(hash_type) { + Ok(hasher) => Hasher(hasher), + Err(error_stack) => panic!("OpenSSL error(s): {}", error_stack), + } + } + + /// Generate a digest from the data written to the `Hasher`. + pub fn finish(&mut self) -> Vec { + let Hasher(ref mut hasher) = *self; + match hasher.finish2() { + Ok(digest) => digest.to_vec(), + Err(error_stack) => panic!("OpenSSL error(s): {}", error_stack), + } + } +} + +impl io::Write for Hasher { + fn write(&mut self, buf: &[u8]) -> io::Result { + let Hasher(ref mut hasher) = *self; + hasher.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + let Hasher(ref mut hasher) = *self; + hasher.flush() + } +} diff --git a/crypto-hash-0.3.0/src/lib.rs b/crypto-hash-0.3.0/src/lib.rs new file mode 100644 index 000000000..3e6f6cd7c --- /dev/null +++ b/crypto-hash-0.3.0/src/lib.rs @@ -0,0 +1,122 @@ +// Copyright (c) 2015, 2016, 2017 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//! A set of [cryptographic hash +//! functions](https://en.wikipedia.org/wiki/Cryptographic_hash_function) provided by the operating +//! system, when available. +//! +//! The purpose of this crate is to provide access to hash algorithms with as few dependencies as +//! possible. This means that when possible, the library uses the hashing functions that are +//! provided by the given operating system's bundled cryptographic libraries. +//! +//! # Supported Implementations +//! +//! By operating system: +//! +//! * Windows: `CryptoAPI` +//! * Mac OS X: `CommonCrypto` +//! * Linux/BSD/etc.: `OpenSSL` +//! +//! # Supported Algorithms +//! +//! * MD5 +//! * SHA1 +//! * SHA256 +//! * SHA512 + +#![warn(missing_docs)] + +#[cfg(target_os = "windows")] +extern crate advapi32; +#[cfg(target_os = "macos")] +extern crate commoncrypto; +extern crate hex; +#[cfg(not(any(target_os = "macos", target_os = "windows")))] +extern crate openssl; +#[cfg(target_os = "windows")] +extern crate winapi; + +use hex::ToHex; +use std::io::Write; + +#[cfg(target_os = "macos")] +#[path = "imp/commoncrypto.rs"] +mod imp; +#[cfg(target_os = "windows")] +#[path = "imp/cryptoapi.rs"] +mod imp; +#[cfg(not(any(target_os = "macos", target_os = "windows")))] +#[path = "imp/openssl.rs"] +mod imp; + +mod test; + +pub use imp::Hasher; + +/// Available cryptographic hash functions. +#[derive(Clone, Debug)] +pub enum Algorithm { + /// Popular message digest algorithm, only available for backwards compatibility purposes. + MD5, + /// SHA-1 algorithm from NIST FIPS, only available for backwards compatibility purposes. + SHA1, + /// SHA-2 family algorithm (256 bits). + SHA256, + /// SHA-2 family algorithm (512 bits). + SHA512, +} + +/// Helper function for `Hasher` which generates a cryptographic digest from the given +/// data and algorithm. +/// +/// # Examples +/// +/// ```rust +/// use crypto_hash::{Algorithm, digest}; +/// +/// let data = b"crypto-hash"; +/// let result = digest(Algorithm::SHA256, data); +/// let expected = +/// b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'" +/// .to_vec(); +/// assert_eq!(expected, result) +/// ``` +pub fn digest(algorithm: Algorithm, data: &[u8]) -> Vec { + let mut hasher = imp::Hasher::new(algorithm); + hasher.write_all(data).expect("Could not write hash data"); + hasher.finish() +} + +/// Helper function for `Hasher` which generates a cryptographic digest serialized in +/// hexadecimal from the given data and algorithm. +/// +/// # Examples +/// +/// ```rust +/// use crypto_hash::{Algorithm, hex_digest}; +/// +/// let data = b"crypto-hash"; +/// let result = hex_digest(Algorithm::SHA256, data); +/// let expected = "fd1afb6022cd4d47c890961c533928eacfe8219f1b2524f7fb2a61847ddf8c27"; +/// assert_eq!(expected, result) +/// ``` +pub fn hex_digest(algorithm: Algorithm, data: &[u8]) -> String { + digest(algorithm, data).to_hex() +} diff --git a/crypto-hash-0.3.0/src/test.rs b/crypto-hash-0.3.0/src/test.rs new file mode 100644 index 000000000..31920c4eb --- /dev/null +++ b/crypto-hash-0.3.0/src/test.rs @@ -0,0 +1,79 @@ +// Copyright (c) 2016, 2017 Mark Lee +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#![cfg(test)] + +use hex::ToHex; +use std::io::Write; +use super::{Algorithm, Hasher, hex_digest}; + +// From Wikipedia +const MD5_EMPTY_STRING: &'static str = "d41d8cd98f00b204e9800998ecf8427e"; +const SHA1_EMPTY_STRING: &'static str = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; +const SHA256_EMPTY_STRING: &'static str = concat!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649", + "b934ca495991b7852b855"); +const SHA512_EMPTY_STRING: &'static str = concat!("cf83e1357eefb8bdf1542850d66d8007d620e4050b5", + "715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318", + "d2877eec2f63b931bd47417a81a538327af927da3e"); +const TO_HASH: &'static str = "The quick brown fox jumps over the lazy dog"; +const TO_HASH_MD5: &'static str = "9e107d9d372bb6826bd81d3542a419d6"; + +#[test] +fn md5_empty_string() { + assert_hex_hashed_empty_string(Algorithm::MD5, MD5_EMPTY_STRING) +} + +#[test] +fn sha1_empty_string() { + assert_hex_hashed_empty_string(Algorithm::SHA1, SHA1_EMPTY_STRING) +} + +#[test] +fn sha256_empty_string() { + // From Wikipedia + assert_hex_hashed_empty_string(Algorithm::SHA256, SHA256_EMPTY_STRING) +} + +#[test] +fn sha512_empty_string() { + assert_hex_hashed_empty_string(Algorithm::SHA512, SHA512_EMPTY_STRING) +} + +#[test] +fn hasher_sans_write() { + let mut hasher = Hasher::new(Algorithm::MD5); + let actual = hasher.finish().to_hex(); + assert_eq!(MD5_EMPTY_STRING, actual) +} + +#[test] +fn hasher_with_write() { + let mut hasher = Hasher::new(Algorithm::MD5); + hasher + .write_all(TO_HASH.as_bytes()) + .expect("Could not write to hasher"); + let actual = hasher.finish().to_hex(); + assert_eq!(TO_HASH_MD5, actual) +} + +fn assert_hex_hashed_empty_string(algorithm: Algorithm, expected: &str) { + let vec = vec![]; + assert_eq!(expected, hex_digest(algorithm, vec.as_slice()).as_str()) +} diff --git a/curl-0.4.11/.cargo-checksum.json b/curl-0.4.11/.cargo-checksum.json new file mode 100644 index 000000000..5e4e759d7 --- /dev/null +++ b/curl-0.4.11/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"b70fd6394677d3c0e239ff4be6f2b3176e171ffd1c23ffdc541e78dea2b8bb5e"} \ No newline at end of file diff --git a/curl-0.4.11/.gitmodules b/curl-0.4.11/.gitmodules new file mode 100644 index 000000000..7196785dd --- /dev/null +++ b/curl-0.4.11/.gitmodules @@ -0,0 +1,3 @@ +[submodule "curl-sys/curl"] + path = curl-sys/curl + url = https://github.com/alexcrichton/curl diff --git a/curl-0.4.11/.travis.yml b/curl-0.4.11/.travis.yml new file mode 100644 index 000000000..d0b3a1f15 --- /dev/null +++ b/curl-0.4.11/.travis.yml @@ -0,0 +1,69 @@ +language: rust +sudo: required +dist: trusty +services: + - docker + +matrix: + include: + - os: linux + rust: stable + env: TARGET=x86_64-unknown-linux-gnu DOCKER=linux64 NO_ADD=1 + - os: linux + rust: stable + env: TARGET=i686-unknown-linux-gnu DOCKER=linux32 + - os: linux + rust: stable + env: TARGET=x86_64-unknown-linux-musl DOCKER=musl + - os: linux + rust: stable + env: TARGET=x86_64-pc-windows-gnu NO_RUN=1 DOCKER=mingw + - os: linux + rust: stable + env: TARGET=x86_64-unknown-linux-gnu DOCKER=linux64-curl NO_ADD=1 + - os: osx + rust: stable + env: TARGET=x86_64-apple-darwin NO_ADD=1 + - os: osx + rust: stable + env: TARGET=i686-apple-darwin + - os: linux + rust: beta + env: TARGET=x86_64-unknown-linux-gnu DOCKER=linux64 NO_ADD=1 + - os: linux + rust: nightly + env: TARGET=x86_64-unknown-linux-gnu DOCKER=linux64 NO_ADD=1 + before_script: + - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH + after_success: + - travis-cargo doc-upload +sudo: false +install: + - if [ -z "$NO_ADD" ]; then rustup target add $TARGET; fi +script: + - curl --version + - cargo generate-lockfile + - cargo generate-lockfile --manifest-path systest/Cargo.toml + - if [ -z "$DOCKER" ]; then + sh ci/run.sh; + else + mkdir .cargo target; + docker build -t rust -f ci/Dockerfile-$DOCKER ci; + docker run + -w /src + -v `pwd`:/src:ro + -v `pwd`/target:/src/target + -v `pwd`/ci/.cargo:/src/.cargo:ro + -v `rustc --print sysroot`:/usr/local:ro + -e TARGET=$TARGET + -e NO_RUN=$NO_RUN + -e CARGO_TARGET_DIR=/src/target + -it rust + sh ci/run.sh; + fi +notifications: + email: + on_success: never +env: + global: + secure: "j4son34/PmqogLMUHgcvOk+XtyUtcd0aAA8Sa/h4pyupw8AEM7+5DMMIrcrRh7ieKqmL2RSSGnYtYbd2b5yYroudypsqmQhK0StzrtPaftl/8zxw8liXzA9rat8MP0vuEAe5w9KLRdFKUCU7TzcYXcKttpbavqdNsJae+OFzHJc=" diff --git a/curl-0.4.11/Cargo.toml b/curl-0.4.11/Cargo.toml new file mode 100644 index 000000000..c48762923 --- /dev/null +++ b/curl-0.4.11/Cargo.toml @@ -0,0 +1,49 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "curl" +version = "0.4.11" +authors = ["Alex Crichton "] +description = "Rust bindings to libcurl for making HTTP requests" +homepage = "https://github.com/alexcrichton/curl-rust" +documentation = "https://docs.rs/curl" +categories = ["api-bindings", "web-programming::http-client"] +license = "MIT" +repository = "https://github.com/alexcrichton/curl-rust" +[dependencies.curl-sys] +version = "0.4.1" + +[dependencies.libc] +version = "0.2" + +[dependencies.socket2] +version = "0.3" +[dev-dependencies.mio] +version = "0.6" +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-probe] +version = "0.1" + +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-sys] +version = "0.9.0" +[target."cfg(target_env=\"msvc\")".dependencies.kernel32-sys] +version = "0.2" + +[target."cfg(target_env=\"msvc\")".dependencies.schannel] +version = "0.1.8" +[target."cfg(windows)".dependencies.winapi] +version = "0.2" +[badges.appveyor] +repository = "alexcrichton/curl-rust" + +[badges.travis-ci] +repository = "alexcrichton/curl-rust" diff --git a/curl-0.4.11/LICENSE b/curl-0.4.11/LICENSE new file mode 100644 index 000000000..5f5e4b09d --- /dev/null +++ b/curl-0.4.11/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 Carl Lerche + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/curl-0.4.11/README.md b/curl-0.4.11/README.md new file mode 100644 index 000000000..7e5a91b2a --- /dev/null +++ b/curl-0.4.11/README.md @@ -0,0 +1,137 @@ +# curl-rust + +libcurl bindings for Rust + +[![Build Status](https://travis-ci.org/alexcrichton/curl-rust.svg?branch=master)](https://travis-ci.org/alexcrichton/curl-rust) +[![Build status](https://ci.appveyor.com/api/projects/status/lx98wtbxhhhajpr9?svg=true)](https://ci.appveyor.com/project/alexcrichton/curl-rust) + +[Documentation](https://docs.rs/curl) + +## Quick Start + +```rust +extern crate curl; + +use std::io::{stdout, Write}; + +use curl::easy::Easy; + +// Print a web page onto stdout +fn main() { + let mut easy = Easy::new(); + easy.url("https://www.rust-lang.org/").unwrap(); + easy.write_function(|data| { + Ok(stdout().write(data).unwrap()) + }).unwrap(); + easy.perform().unwrap(); + + println!("{}", easy.response_code().unwrap()); +} +``` + +```rust +extern crate curl; + +use curl::easy::Easy; + +// Capture output into a local `Vec`. +fn main() { + let mut dst = Vec::new(); + let mut easy = Easy::new(); + easy.url("https://www.rust-lang.org/").unwrap(); + + let mut transfer = easy.transfer(); + transfer.write_function(|data| { + dst.extend_from_slice(data); + Ok(data.len()) + }).unwrap(); + transfer.perform().unwrap(); +} +``` + +## Post / Put requests + +The `put` and `post` methods on `Easy` can configure the method of the HTTP +request, and then `read_function` can be used to specify how data is filled in. +This interface works particularly well with types that implement `Read`. + +```rust,no_run +extern crate curl; + +use std::io::Read; +use curl::easy::Easy; + +fn main() { + let mut data = "this is the body".as_bytes(); + + let mut easy = Easy::new(); + easy.url("http://www.example.com/upload").unwrap(); + easy.post(true).unwrap(); + easy.post_field_size(data.len() as u64).unwrap(); + + let mut transfer = easy.transfer(); + transfer.read_function(|buf| { + Ok(data.read(buf).unwrap_or(0)) + }).unwrap(); + transfer.perform().unwrap(); +} +``` + +## Custom headers + +Custom headers can be specified as part of the request: + +```rust,no_run +extern crate curl; + +use curl::easy::{Easy, List}; + +fn main() { + let mut easy = Easy::new(); + easy.url("http://www.example.com").unwrap(); + + let mut list = List::new(); + list.append("Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==").unwrap(); + easy.http_headers(list).unwrap(); + easy.perform().unwrap(); +} +``` + +## Keep alive + +The handle can be re-used across multiple requests. Curl will attempt to +keep the connections alive. + +```rust,no_run +extern crate curl; + +use curl::easy::Easy; + +fn main() { + let mut handle = Easy::new(); + + handle.url("http://www.example.com/foo").unwrap(); + handle.perform().unwrap(); + + handle.url("http://www.example.com/bar").unwrap(); + handle.perform().unwrap(); +} +``` + +## Multiple requests + +The libcurl library provides support for sending multiple requests +simultaneously through the "multi" interface. This is currently bound in the +`multi` module of this crate and provides the ability to execute multiple +transfers simultaneously. For more information, see that module. + +## Version Support + +The bindings have been developed using curl version 7.24.0. They should +work with any newer version of curl and possibly with older versions, +but this has not been tested. + +## License + +The `curl-rust` crate is licensed under the MIT license, see `LICENSE` for more +details. diff --git a/curl-0.4.11/appveyor.yml b/curl-0.4.11/appveyor.yml new file mode 100644 index 000000000..bf194d375 --- /dev/null +++ b/curl-0.4.11/appveyor.yml @@ -0,0 +1,69 @@ +environment: + matrix: + + # Ensure MinGW works, but we need to download the 32-bit MinGW compiler from a + # custom location. + - TARGET: i686-pc-windows-gnu + MINGW_URL: https://s3.amazonaws.com/rust-lang-ci + MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z + MINGW_DIR: mingw32 + - TARGET: x86_64-pc-windows-gnu + MSYS_BITS: 64 + + # Ensure vanilla builds work + - TARGET: i686-pc-windows-msvc + - TARGET: x86_64-pc-windows-msvc + + # Pin to specific VS versions to ensure the build works + - TARGET: x86_64-pc-windows-msvc + ARCH: amd64 + VS: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat + - TARGET: x86_64-pc-windows-msvc + ARCH: amd64 + VS: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat + + # Ensure getting libcurl from vcpkg works + - TARGET: x86_64-pc-windows-msvc + VCPKGRS_DYNAMIC: 1 + VCPKG_DEFAULT_TRIPLET: x64-windows + +install: + # Install rust, x86_64-pc-windows-msvc host + - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe + # use nightly if required until -Ctarget-feature=+crt-static is stable (expected in rust 1.19) + - if not defined RUSTFLAGS rustup-init.exe -y --default-host x86_64-pc-windows-msvc + - if defined RUSTFLAGS rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly + - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin + + # Install the target we're compiling for + - if NOT "%TARGET%" == "x86_64-pc-windows-msvc" rustup target add %TARGET% + + # Use the system msys if we can + - if defined MSYS_BITS set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH% + + # download a custom compiler otherwise + - if defined MINGW_URL appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE% + - if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul + - if defined MINGW_URL set PATH=C:\Python27;%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH% + + # If we're pinning to a specific visual studio, do so now + - if defined VS call "%VS%" %ARCH% + + # let's see what we got + - where gcc rustc cargo + - rustc -vV + - cargo -vV + - set CARGO_TARGET_DIR=%CD%\target + + # install vcpkg if required + - if defined VCPKG_DEFAULT_TRIPLET git clone https://github.com/Microsoft/vcpkg c:\projects\vcpkg + - if defined VCPKG_DEFAULT_TRIPLET c:\projects\vcpkg\bootstrap-vcpkg.bat + - if defined VCPKG_DEFAULT_TRIPLET set VCPKG_ROOT=c:\projects\vcpkg + - if defined VCPKG_DEFAULT_TRIPLET echo yes > %VCPKG_ROOT%\Downloads\AlwaysAllowDownloads + - if defined VCPKG_DEFAULT_TRIPLET %VCPKG_ROOT%\vcpkg.exe install curl + +build: false + +test_script: + - cargo test --target %TARGET% + - cargo run --manifest-path systest/Cargo.toml --target %TARGET% diff --git a/curl-0.4.11/ci/.cargo/config b/curl-0.4.11/ci/.cargo/config new file mode 100644 index 000000000..5ed633890 --- /dev/null +++ b/curl-0.4.11/ci/.cargo/config @@ -0,0 +1,2 @@ +[target.x86_64-pc-windows-gnu] +linker = "x86_64-w64-mingw32-gcc" diff --git a/curl-0.4.11/ci/Dockerfile-linux32 b/curl-0.4.11/ci/Dockerfile-linux32 new file mode 100644 index 000000000..4d55dcf04 --- /dev/null +++ b/curl-0.4.11/ci/Dockerfile-linux32 @@ -0,0 +1,14 @@ +FROM ubuntu:16.04 + +RUN dpkg --add-architecture i386 && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + gcc-multilib \ + ca-certificates \ + make \ + libc6-dev \ + libssl-dev:i386 \ + pkg-config + +ENV PKG_CONFIG=i686-linux-gnu-pkg-config \ + PKG_CONFIG_ALLOW_CROSS=1 diff --git a/curl-0.4.11/ci/Dockerfile-linux64 b/curl-0.4.11/ci/Dockerfile-linux64 new file mode 100644 index 000000000..a5c1fe37f --- /dev/null +++ b/curl-0.4.11/ci/Dockerfile-linux64 @@ -0,0 +1,9 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc ca-certificates make libc6-dev \ + libssl-dev \ + pkg-config + +ENV FEATURES="http2" \ No newline at end of file diff --git a/curl-0.4.11/ci/Dockerfile-linux64-curl b/curl-0.4.11/ci/Dockerfile-linux64-curl new file mode 100644 index 000000000..be03c24da --- /dev/null +++ b/curl-0.4.11/ci/Dockerfile-linux64-curl @@ -0,0 +1,6 @@ +FROM ubuntu:14.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc ca-certificates make libc6-dev \ + libssl-dev libcurl4-openssl-dev pkg-config diff --git a/curl-0.4.11/ci/Dockerfile-mingw b/curl-0.4.11/ci/Dockerfile-mingw new file mode 100644 index 000000000..ee5926c8d --- /dev/null +++ b/curl-0.4.11/ci/Dockerfile-mingw @@ -0,0 +1,6 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc ca-certificates make libc6-dev \ + gcc-mingw-w64-x86-64 libz-mingw-w64-dev diff --git a/curl-0.4.11/ci/Dockerfile-musl b/curl-0.4.11/ci/Dockerfile-musl new file mode 100644 index 000000000..47d211fdf --- /dev/null +++ b/curl-0.4.11/ci/Dockerfile-musl @@ -0,0 +1,18 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y --no-install-recommends \ + gcc ca-certificates make libc6-dev curl \ + musl-tools + +RUN \ + curl https://www.openssl.org/source/old/1.0.2/openssl-1.0.2g.tar.gz | tar xzf - && \ + cd openssl-1.0.2g && \ + CC=musl-gcc ./Configure --prefix=/openssl no-dso linux-x86_64 -fPIC && \ + make -j10 && \ + make install && \ + cd .. && \ + rm -rf openssl-1.0.2g + +ENV OPENSSL_STATIC=1 \ + OPENSSL_DIR=/openssl diff --git a/curl-0.4.11/ci/run.sh b/curl-0.4.11/ci/run.sh new file mode 100644 index 000000000..239d0b8c1 --- /dev/null +++ b/curl-0.4.11/ci/run.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +set -ex + +cargo test --target $TARGET --no-run +if [ -z "$NO_RUN" ]; then + cargo test --target $TARGET + cargo run --manifest-path systest/Cargo.toml --target $TARGET + cargo doc --no-deps --target $TARGET + cargo doc --no-deps -p curl-sys --target $TARGET +fi + +if [ -n "$FEATURES" ] +then + cargo run --manifest-path systest/Cargo.toml --target $TARGET --features "$FEATURES" +fi diff --git a/curl-0.4.11/src/easy/form.rs b/curl-0.4.11/src/easy/form.rs new file mode 100644 index 000000000..be98d4e8e --- /dev/null +++ b/curl-0.4.11/src/easy/form.rs @@ -0,0 +1,333 @@ +use std::ffi::CString; +use std::fmt; +use std::path::Path; + +use FormError; +use curl_sys; +use easy::{list, List}; + +/// Multipart/formdata for an HTTP POST request. +/// +/// This structure is built up and then passed to the `Easy::httppost` method to +/// be sent off with a request. +pub struct Form { + head: *mut curl_sys::curl_httppost, + tail: *mut curl_sys::curl_httppost, + headers: Vec, + buffers: Vec>, + strings: Vec, +} + +/// One part in a multipart upload, added to a `Form`. +pub struct Part<'form, 'data> { + form: &'form mut Form, + name: &'data str, + array: Vec, + error: Option, +} + +pub fn raw(form: &Form) -> *mut curl_sys::curl_httppost { + form.head +} + +impl Form { + /// Creates a new blank form ready for the addition of new data. + pub fn new() -> Form { + Form { + head: 0 as *mut _, + tail: 0 as *mut _, + headers: Vec::new(), + buffers: Vec::new(), + strings: Vec::new(), + } + } + + /// Prepares adding a new part to this `Form` + /// + /// Note that the part is not actually added to the form until the `add` + /// method is called on `Part`, which may or may not fail. + pub fn part<'a, 'data>(&'a mut self, name: &'data str) -> Part<'a, 'data> { + Part { + error: None, + form: self, + name: name, + array: vec![curl_sys::curl_forms { + option: curl_sys::CURLFORM_END, + value: 0 as *mut _, + }], + } + } +} + +impl fmt::Debug for Form { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // TODO: fill this out more + f.debug_struct("Form") + .field("fields", &"...") + .finish() + } +} + +impl Drop for Form { + fn drop(&mut self) { + unsafe { + curl_sys::curl_formfree(self.head); + } + } +} + +impl<'form, 'data> Part<'form, 'data> { + /// A pointer to the contents of this part, the actual data to send away. + pub fn contents(&mut self, contents: &'data [u8]) -> &mut Self { + let pos = self.array.len() - 1; + + // curl has an oddity where if the length if 0 it will call strlen + // on the value. This means that if someone wants to add empty form + // contents we need to make sure the buffer contains a null byte. + let ptr = if contents.is_empty() { + b"\x00" + } else { + contents + }.as_ptr(); + + self.array.insert(pos, curl_sys::curl_forms { + option: curl_sys::CURLFORM_COPYCONTENTS, + value: ptr as *mut _, + }); + self.array.insert(pos + 1, curl_sys::curl_forms { + option: curl_sys::CURLFORM_CONTENTSLENGTH, + value: contents.len() as *mut _, + }); + self + } + + /// Causes this file to be read and its contents used as data in this part + /// + /// This part does not automatically become a file upload part simply + /// because its data was read from a file. + /// + /// # Errors + /// + /// If the filename has any internal nul bytes or if on Windows it does not + /// contain a unicode filename then the `add` function will eventually + /// return an error. + pub fn file_content

(&mut self, file: P) -> &mut Self + where P: AsRef + { + self._file_content(file.as_ref()) + } + + fn _file_content(&mut self, file: &Path) -> &mut Self { + if let Some(bytes) = self.path2cstr(file) { + let pos = self.array.len() - 1; + self.array.insert(pos, curl_sys::curl_forms { + option: curl_sys::CURLFORM_FILECONTENT, + value: bytes.as_ptr() as *mut _, + }); + self.form.strings.push(bytes); + } + self + } + + /// Makes this part a file upload part of the given file. + /// + /// Sets the filename field to the basename of the provided file name, and + /// it reads the contents of the file and passes them as data and sets the + /// content type if the given file matches one of the internally known file + /// extensions. + /// + /// The given upload file must exist entirely on the filesystem before the + /// upload is started because libcurl needs to read the size of it + /// beforehand. + /// + /// Multiple files can be uploaded by calling this method multiple times and + /// content types can also be configured for each file (by calling that + /// next). + /// + /// # Errors + /// + /// If the filename has any internal nul bytes or if on Windows it does not + /// contain a unicode filename then this function will cause `add` to return + /// an error when called. + pub fn file(&mut self, file: &'data P) -> &mut Self + where P: AsRef + { + self._file(file.as_ref()) + } + + fn _file(&mut self, file: &'data Path) -> &mut Self { + if let Some(bytes) = self.path2cstr(file) { + let pos = self.array.len() - 1; + self.array.insert(pos, curl_sys::curl_forms { + option: curl_sys::CURLFORM_FILE, + value: bytes.as_ptr() as *mut _, + }); + self.form.strings.push(bytes); + } + self + } + + /// Used in combination with `Part::file`, provides the content-type for + /// this part, possibly instead of choosing an internal one. + /// + /// # Panics + /// + /// This function will panic if `content_type` contains an internal nul + /// byte. + pub fn content_type(&mut self, content_type: &'data str) -> &mut Self { + if let Some(bytes) = self.bytes2cstr(content_type.as_bytes()) { + let pos = self.array.len() - 1; + self.array.insert(pos, curl_sys::curl_forms { + option: curl_sys::CURLFORM_CONTENTTYPE, + value: bytes.as_ptr() as *mut _, + }); + self.form.strings.push(bytes); + } + self + } + + /// Used in combination with `Part::file`, provides the filename for + /// this part instead of the actual one. + /// + /// # Errors + /// + /// If `name` contains an internal nul byte, or if on Windows the path is + /// not valid unicode then this function will return an error when `add` is + /// called. + pub fn filename(&mut self, name: &'data P) -> &mut Self + where P: AsRef + { + self._filename(name.as_ref()) + } + + fn _filename(&mut self, name: &'data Path) -> &mut Self { + if let Some(bytes) = self.path2cstr(name) { + let pos = self.array.len() - 1; + self.array.insert(pos, curl_sys::curl_forms { + option: curl_sys::CURLFORM_FILENAME, + value: bytes.as_ptr() as *mut _, + }); + self.form.strings.push(bytes); + } + self + } + + /// This is used to provide a custom file upload part without using the + /// `file` method above. + /// + /// The first parameter is for the filename field and the second is the + /// in-memory contents. + /// + /// # Errors + /// + /// If `name` contains an internal nul byte, or if on Windows the path is + /// not valid unicode then this function will return an error when `add` is + /// called. + pub fn buffer(&mut self, name: &'data P, data: Vec) + -> &mut Self + where P: AsRef + { + self._buffer(name.as_ref(), data) + } + + fn _buffer(&mut self, name: &'data Path, data: Vec) -> &mut Self { + if let Some(bytes) = self.path2cstr(name) { + let pos = self.array.len() - 1; + self.array.insert(pos, curl_sys::curl_forms { + option: curl_sys::CURLFORM_BUFFER, + value: bytes.as_ptr() as *mut _, + }); + self.form.strings.push(bytes); + self.array.insert(pos + 1, curl_sys::curl_forms { + option: curl_sys::CURLFORM_BUFFERPTR, + value: data.as_ptr() as *mut _, + }); + self.array.insert(pos + 2, curl_sys::curl_forms { + option: curl_sys::CURLFORM_BUFFERLENGTH, + value: data.len() as *mut _, + }); + self.form.buffers.push(data); + } + self + } + + /// Specifies extra headers for the form POST section. + /// + /// Appends the list of headers to those libcurl automatically generates. + pub fn content_header(&mut self, headers: List) -> &mut Self { + let pos = self.array.len() - 1; + self.array.insert(pos, curl_sys::curl_forms { + option: curl_sys::CURLFORM_CONTENTHEADER, + value: list::raw(&headers) as *mut _, + }); + self.form.headers.push(headers); + self + } + + /// Attempts to add this part to the `Form` that it was created from. + /// + /// If any error happens while adding, that error is returned, otherwise + /// `Ok(())` is returned. + pub fn add(&mut self) -> Result<(), FormError> { + if let Some(err) = self.error.clone() { + return Err(err) + } + let rc = unsafe { + curl_sys::curl_formadd(&mut self.form.head, + &mut self.form.tail, + curl_sys::CURLFORM_COPYNAME, + self.name.as_ptr(), + curl_sys::CURLFORM_NAMELENGTH, + self.name.len(), + curl_sys::CURLFORM_ARRAY, + self.array.as_ptr(), + curl_sys::CURLFORM_END) + }; + if rc == curl_sys::CURL_FORMADD_OK { + Ok(()) + } else { + Err(FormError::new(rc)) + } + } + + #[cfg(unix)] + fn path2cstr(&mut self, p: &Path) -> Option { + use std::os::unix::prelude::*; + self.bytes2cstr(p.as_os_str().as_bytes()) + } + + #[cfg(windows)] + fn path2cstr(&mut self, p: &Path) -> Option { + match p.to_str() { + Some(bytes) => self.bytes2cstr(bytes.as_bytes()), + None if self.error.is_none() => { + // TODO: better error code + self.error = Some(FormError::new(curl_sys::CURL_FORMADD_INCOMPLETE)); + None + } + None => None, + } + } + + fn bytes2cstr(&mut self, bytes: &[u8]) -> Option { + match CString::new(bytes) { + Ok(c) => Some(c), + Err(..) if self.error.is_none() => { + // TODO: better error code + self.error = Some(FormError::new(curl_sys::CURL_FORMADD_INCOMPLETE)); + None + } + Err(..) => None, + } + } +} + +impl<'form, 'data> fmt::Debug for Part<'form, 'data> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // TODO: fill this out more + f.debug_struct("Part") + .field("name", &self.name) + .field("form", &self.form) + .finish() + } +} diff --git a/curl-0.4.11/src/easy/handle.rs b/curl-0.4.11/src/easy/handle.rs new file mode 100644 index 000000000..ac6d37f7e --- /dev/null +++ b/curl-0.4.11/src/easy/handle.rs @@ -0,0 +1,1446 @@ +use std::cell::Cell; +use std::fmt; +use std::io::SeekFrom; +use std::path::Path; +use std::ptr; +use std::str; +use std::time::Duration; + +use curl_sys; +use libc::c_void; + +use Error; +use easy::{Form, List}; +use easy::handler::{self, InfoType, SeekResult, ReadError, WriteError}; +use easy::handler::{TimeCondition, IpResolve, HttpVersion, SslVersion}; +use easy::handler::{SslOpt, NetRc, Auth, ProxyType}; +use easy::{Easy2, Handler}; + +/// Raw bindings to a libcurl "easy session". +/// +/// This type is the same as the `Easy2` type in this library except that it +/// does not contain a type parameter. Callbacks from curl are all controlled +/// via closures on this `Easy` type, and this type namely has a `transfer` +/// method as well for ergonomic management of these callbacks. +/// +/// There's not necessarily a right answer for which type is correct to use, but +/// as a general rule of thumb `Easy` is typically a reasonable choice for +/// synchronous I/O and `Easy2` is a good choice for asynchronous I/O. +/// +/// ## Examples +/// +/// Creating a handle which can be used later +/// +/// ``` +/// use curl::easy::Easy; +/// +/// let handle = Easy::new(); +/// ``` +/// +/// Send an HTTP request, writing the response to stdout. +/// +/// ``` +/// use std::io::{stdout, Write}; +/// +/// use curl::easy::Easy; +/// +/// let mut handle = Easy::new(); +/// handle.url("https://www.rust-lang.org/").unwrap(); +/// handle.write_function(|data| { +/// Ok(stdout().write(data).unwrap()) +/// }).unwrap(); +/// handle.perform().unwrap(); +/// ``` +/// +/// Collect all output of an HTTP request to a vector. +/// +/// ``` +/// use curl::easy::Easy; +/// +/// let mut data = Vec::new(); +/// let mut handle = Easy::new(); +/// handle.url("https://www.rust-lang.org/").unwrap(); +/// { +/// let mut transfer = handle.transfer(); +/// transfer.write_function(|new_data| { +/// data.extend_from_slice(new_data); +/// Ok(new_data.len()) +/// }).unwrap(); +/// transfer.perform().unwrap(); +/// } +/// println!("{:?}", data); +/// ``` +/// +/// More examples of various properties of an HTTP request can be found on the +/// specific methods as well. +#[derive(Debug)] +pub struct Easy { + inner: Easy2, +} + +/// A scoped transfer of information which borrows an `Easy` and allows +/// referencing stack-local data of the lifetime `'data`. +/// +/// Usage of `Easy` requires the `'static` and `Send` bounds on all callbacks +/// registered, but that's not often wanted if all you need is to collect a +/// bunch of data in memory to a vector, for example. The `Transfer` structure, +/// created by the `Easy::transfer` method, is used for this sort of request. +/// +/// The callbacks attached to a `Transfer` are only active for that one transfer +/// object, and they allow to elide both the `Send` and `'static` bounds to +/// close over stack-local information. +pub struct Transfer<'easy, 'data> { + easy: &'easy mut Easy, + data: Box>, +} + +pub struct EasyData { + running: Cell, + owned: Callbacks<'static>, + borrowed: Cell<*mut Callbacks<'static>>, +} + +unsafe impl Send for EasyData {} + +#[derive(Default)] +struct Callbacks<'a> { + write: Option Result + 'a>>, + read: Option Result + 'a>>, + seek: Option SeekResult + 'a>>, + debug: Option>, + header: Option bool + 'a>>, + progress: Option bool + 'a>>, + ssl_ctx: Option Result<(), Error> + 'a>>, +} + +impl Easy { + /// Creates a new "easy" handle which is the core of almost all operations + /// in libcurl. + /// + /// To use a handle, applications typically configure a number of options + /// followed by a call to `perform`. Options are preserved across calls to + /// `perform` and need to be reset manually (or via the `reset` method) if + /// this is not desired. + pub fn new() -> Easy { + Easy { + inner: Easy2::new(EasyData { + running: Cell::new(false), + owned: Callbacks::default(), + borrowed: Cell::new(ptr::null_mut()), + }), + } + } + + // ========================================================================= + // Behavior options + + /// Same as [`Easy2::verbose`](struct.Easy2.html#method.verbose) + pub fn verbose(&mut self, verbose: bool) -> Result<(), Error> { + self.inner.verbose(verbose) + } + + /// Same as [`Easy2::show_header`](struct.Easy2.html#method.show_header) + pub fn show_header(&mut self, show: bool) -> Result<(), Error> { + self.inner.show_header(show) + } + + /// Same as [`Easy2::progress`](struct.Easy2.html#method.progress) + pub fn progress(&mut self, progress: bool) -> Result<(), Error> { + self.inner.progress(progress) + } + + /// Same as [`Easy2::signal`](struct.Easy2.html#method.signal) + pub fn signal(&mut self, signal: bool) -> Result<(), Error> { + self.inner.signal(signal) + } + + /// Same as [`Easy2::wildcard_match`](struct.Easy2.html#method.wildcard_match) + pub fn wildcard_match(&mut self, m: bool) -> Result<(), Error> { + self.inner.wildcard_match(m) + } + + /// Same as [`Easy2::unix_socket`](struct.Easy2.html#method.unix_socket) + pub fn unix_socket(&mut self, unix_domain_socket: &str) -> Result<(), Error> { + self.inner.unix_socket(unix_domain_socket) + } + + // ========================================================================= + // Callback options + + /// Set callback for writing received data. + /// + /// This callback function gets called by libcurl as soon as there is data + /// received that needs to be saved. + /// + /// The callback function will be passed as much data as possible in all + /// invokes, but you must not make any assumptions. It may be one byte, it + /// may be thousands. If `show_header` is enabled, which makes header data + /// get passed to the write callback, you can get up to + /// `CURL_MAX_HTTP_HEADER` bytes of header data passed into it. This + /// usually means 100K. + /// + /// This function may be called with zero bytes data if the transferred file + /// is empty. + /// + /// The callback should return the number of bytes actually taken care of. + /// If that amount differs from the amount passed to your callback function, + /// it'll signal an error condition to the library. This will cause the + /// transfer to get aborted and the libcurl function used will return + /// an error with `is_write_error`. + /// + /// If your callback function returns `Err(WriteError::Pause)` it will cause + /// this transfer to become paused. See `unpause_write` for further details. + /// + /// By default data is sent into the void, and this corresponds to the + /// `CURLOPT_WRITEFUNCTION` and `CURLOPT_WRITEDATA` options. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `write_function` to configure a + /// callback that can reference stack-local data. + /// + /// # Examples + /// + /// ``` + /// use std::io::{stdout, Write}; + /// use curl::easy::Easy; + /// + /// let mut handle = Easy::new(); + /// handle.url("https://www.rust-lang.org/").unwrap(); + /// handle.write_function(|data| { + /// Ok(stdout().write(data).unwrap()) + /// }).unwrap(); + /// handle.perform().unwrap(); + /// ``` + /// + /// Writing to a stack-local buffer + /// + /// ``` + /// use std::io::{stdout, Write}; + /// use curl::easy::Easy; + /// + /// let mut buf = Vec::new(); + /// let mut handle = Easy::new(); + /// handle.url("https://www.rust-lang.org/").unwrap(); + /// + /// let mut transfer = handle.transfer(); + /// transfer.write_function(|data| { + /// buf.extend_from_slice(data); + /// Ok(data.len()) + /// }).unwrap(); + /// transfer.perform().unwrap(); + /// ``` + pub fn write_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(&[u8]) -> Result + Send + 'static + { + self.inner.get_mut().owned.write = Some(Box::new(f)); + Ok(()) + } + + /// Read callback for data uploads. + /// + /// This callback function gets called by libcurl as soon as it needs to + /// read data in order to send it to the peer - like if you ask it to upload + /// or post data to the server. + /// + /// Your function must then return the actual number of bytes that it stored + /// in that memory area. Returning 0 will signal end-of-file to the library + /// and cause it to stop the current transfer. + /// + /// If you stop the current transfer by returning 0 "pre-maturely" (i.e + /// before the server expected it, like when you've said you will upload N + /// bytes and you upload less than N bytes), you may experience that the + /// server "hangs" waiting for the rest of the data that won't come. + /// + /// The read callback may return `Err(ReadError::Abort)` to stop the + /// current operation immediately, resulting in a `is_aborted_by_callback` + /// error code from the transfer. + /// + /// The callback can return `Err(ReadError::Pause)` to cause reading from + /// this connection to pause. See `unpause_read` for further details. + /// + /// By default data not input, and this corresponds to the + /// `CURLOPT_READFUNCTION` and `CURLOPT_READDATA` options. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `read_function` to configure a + /// callback that can reference stack-local data. + /// + /// # Examples + /// + /// Read input from stdin + /// + /// ```no_run + /// use std::io::{stdin, Read}; + /// use curl::easy::Easy; + /// + /// let mut handle = Easy::new(); + /// handle.url("https://example.com/login").unwrap(); + /// handle.read_function(|into| { + /// Ok(stdin().read(into).unwrap()) + /// }).unwrap(); + /// handle.post(true).unwrap(); + /// handle.perform().unwrap(); + /// ``` + /// + /// Reading from stack-local data: + /// + /// ```no_run + /// use std::io::{stdin, Read}; + /// use curl::easy::Easy; + /// + /// let mut data_to_upload = &b"foobar"[..]; + /// let mut handle = Easy::new(); + /// handle.url("https://example.com/login").unwrap(); + /// handle.post(true).unwrap(); + /// + /// let mut transfer = handle.transfer(); + /// transfer.read_function(|into| { + /// Ok(data_to_upload.read(into).unwrap()) + /// }).unwrap(); + /// transfer.perform().unwrap(); + /// ``` + pub fn read_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(&mut [u8]) -> Result + Send + 'static + { + self.inner.get_mut().owned.read = Some(Box::new(f)); + Ok(()) + } + + /// User callback for seeking in input stream. + /// + /// This function gets called by libcurl to seek to a certain position in + /// the input stream and can be used to fast forward a file in a resumed + /// upload (instead of reading all uploaded bytes with the normal read + /// function/callback). It is also called to rewind a stream when data has + /// already been sent to the server and needs to be sent again. This may + /// happen when doing a HTTP PUT or POST with a multi-pass authentication + /// method, or when an existing HTTP connection is reused too late and the + /// server closes the connection. + /// + /// The callback function must return `SeekResult::Ok` on success, + /// `SeekResult::Fail` to cause the upload operation to fail or + /// `SeekResult::CantSeek` to indicate that while the seek failed, libcurl + /// is free to work around the problem if possible. The latter can sometimes + /// be done by instead reading from the input or similar. + /// + /// By default data this option is not set, and this corresponds to the + /// `CURLOPT_SEEKFUNCTION` and `CURLOPT_SEEKDATA` options. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `seek_function` to configure a + /// callback that can reference stack-local data. + pub fn seek_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(SeekFrom) -> SeekResult + Send + 'static + { + self.inner.get_mut().owned.seek = Some(Box::new(f)); + Ok(()) + } + + /// Callback to progress meter function + /// + /// This function gets called by libcurl instead of its internal equivalent + /// with a frequent interval. While data is being transferred it will be + /// called very frequently, and during slow periods like when nothing is + /// being transferred it can slow down to about one call per second. + /// + /// The callback gets told how much data libcurl will transfer and has + /// transferred, in number of bytes. The first argument is the total number + /// of bytes libcurl expects to download in this transfer. The second + /// argument is the number of bytes downloaded so far. The third argument is + /// the total number of bytes libcurl expects to upload in this transfer. + /// The fourth argument is the number of bytes uploaded so far. + /// + /// Unknown/unused argument values passed to the callback will be set to + /// zero (like if you only download data, the upload size will remain 0). + /// Many times the callback will be called one or more times first, before + /// it knows the data sizes so a program must be made to handle that. + /// + /// Returning `false` from this callback will cause libcurl to abort the + /// transfer and return `is_aborted_by_callback`. + /// + /// If you transfer data with the multi interface, this function will not be + /// called during periods of idleness unless you call the appropriate + /// libcurl function that performs transfers. + /// + /// `progress` must be set to `true` to make this function actually get + /// called. + /// + /// By default this function calls an internal method and corresponds to + /// `CURLOPT_PROGRESSFUNCTION` and `CURLOPT_PROGRESSDATA`. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `progress_function` to configure a + /// callback that can reference stack-local data. + pub fn progress_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(f64, f64, f64, f64) -> bool + Send + 'static + { + self.inner.get_mut().owned.progress = Some(Box::new(f)); + Ok(()) + } + + /// Callback to SSL context + /// + /// This callback function gets called by libcurl just before the + /// initialization of an SSL connection after having processed all + /// other SSL related options to give a last chance to an + /// application to modify the behaviour of the SSL + /// initialization. The `ssl_ctx` parameter is actually a pointer + /// to the SSL library's SSL_CTX. If an error is returned from the + /// callback no attempt to establish a connection is made and the + /// perform operation will return the callback's error code. + /// + /// This function will get called on all new connections made to a + /// server, during the SSL negotiation. The SSL_CTX pointer will + /// be a new one every time. + /// + /// To use this properly, a non-trivial amount of knowledge of + /// your SSL library is necessary. For example, you can use this + /// function to call library-specific callbacks to add additional + /// validation code for certificates, and even to change the + /// actual URI of a HTTPS request. + /// + /// By default this function calls an internal method and + /// corresponds to `CURLOPT_SSL_CTX_FUNCTION` and + /// `CURLOPT_SSL_CTX_DATA`. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `progress_function` to configure a + /// callback that can reference stack-local data. + pub fn ssl_ctx_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(*mut c_void) -> Result<(), Error> + Send + 'static + { + self.inner.get_mut().owned.ssl_ctx = Some(Box::new(f)); + Ok(()) + } + + /// Specify a debug callback + /// + /// `debug_function` replaces the standard debug function used when + /// `verbose` is in effect. This callback receives debug information, + /// as specified in the type argument. + /// + /// By default this option is not set and corresponds to the + /// `CURLOPT_DEBUGFUNCTION` and `CURLOPT_DEBUGDATA` options. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `debug_function` to configure a + /// callback that can reference stack-local data. + pub fn debug_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(InfoType, &[u8]) + Send + 'static + { + self.inner.get_mut().owned.debug = Some(Box::new(f)); + Ok(()) + } + + /// Callback that receives header data + /// + /// This function gets called by libcurl as soon as it has received header + /// data. The header callback will be called once for each header and only + /// complete header lines are passed on to the callback. Parsing headers is + /// very easy using this. If this callback returns `false` it'll signal an + /// error to the library. This will cause the transfer to get aborted and + /// the libcurl function in progress will return `is_write_error`. + /// + /// A complete HTTP header that is passed to this function can be up to + /// CURL_MAX_HTTP_HEADER (100K) bytes. + /// + /// It's important to note that the callback will be invoked for the headers + /// of all responses received after initiating a request and not just the + /// final response. This includes all responses which occur during + /// authentication negotiation. If you need to operate on only the headers + /// from the final response, you will need to collect headers in the + /// callback yourself and use HTTP status lines, for example, to delimit + /// response boundaries. + /// + /// When a server sends a chunked encoded transfer, it may contain a + /// trailer. That trailer is identical to a HTTP header and if such a + /// trailer is received it is passed to the application using this callback + /// as well. There are several ways to detect it being a trailer and not an + /// ordinary header: 1) it comes after the response-body. 2) it comes after + /// the final header line (CR LF) 3) a Trailer: header among the regular + /// response-headers mention what header(s) to expect in the trailer. + /// + /// For non-HTTP protocols like FTP, POP3, IMAP and SMTP this function will + /// get called with the server responses to the commands that libcurl sends. + /// + /// By default this option is not set and corresponds to the + /// `CURLOPT_HEADERFUNCTION` and `CURLOPT_HEADERDATA` options. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `header_function` to configure a + /// callback that can reference stack-local data. + /// + /// # Examples + /// + /// ``` + /// use std::str; + /// + /// use curl::easy::Easy; + /// + /// let mut handle = Easy::new(); + /// handle.url("https://www.rust-lang.org/").unwrap(); + /// handle.header_function(|header| { + /// print!("header: {}", str::from_utf8(header).unwrap()); + /// true + /// }).unwrap(); + /// handle.perform().unwrap(); + /// ``` + /// + /// Collecting headers to a stack local vector + /// + /// ``` + /// use std::str; + /// + /// use curl::easy::Easy; + /// + /// let mut headers = Vec::new(); + /// let mut handle = Easy::new(); + /// handle.url("https://www.rust-lang.org/").unwrap(); + /// + /// { + /// let mut transfer = handle.transfer(); + /// transfer.header_function(|header| { + /// headers.push(str::from_utf8(header).unwrap().to_string()); + /// true + /// }).unwrap(); + /// transfer.perform().unwrap(); + /// } + /// + /// println!("{:?}", headers); + /// ``` + pub fn header_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(&[u8]) -> bool + Send + 'static + { + self.inner.get_mut().owned.header = Some(Box::new(f)); + Ok(()) + } + + // ========================================================================= + // Error options + + // TODO: error buffer and stderr + + /// Same as [`Easy2::fail_on_error`](struct.Easy2.html#method.fail_on_error) + pub fn fail_on_error(&mut self, fail: bool) -> Result<(), Error> { + self.inner.fail_on_error(fail) + } + + // ========================================================================= + // Network options + + /// Same as [`Easy2::url`](struct.Easy2.html#method.url) + pub fn url(&mut self, url: &str) -> Result<(), Error> { + self.inner.url(url) + } + + /// Same as [`Easy2::port`](struct.Easy2.html#method.port) + pub fn port(&mut self, port: u16) -> Result<(), Error> { + self.inner.port(port) + } + + /// Same as [`Easy2::proxy`](struct.Easy2.html#method.proxy) + pub fn proxy(&mut self, url: &str) -> Result<(), Error> { + self.inner.proxy(url) + } + + /// Same as [`Easy2::proxy_port`](struct.Easy2.html#method.proxy_port) + pub fn proxy_port(&mut self, port: u16) -> Result<(), Error> { + self.inner.proxy_port(port) + } + + /// Same as [`Easy2::proxy_type`](struct.Easy2.html#method.proxy_type) + pub fn proxy_type(&mut self, kind: ProxyType) -> Result<(), Error> { + self.inner.proxy_type(kind) + } + + /// Same as [`Easy2::noproxy`](struct.Easy2.html#method.noproxy) + pub fn noproxy(&mut self, skip: &str) -> Result<(), Error> { + self.inner.noproxy(skip) + } + + /// Same as [`Easy2::http_proxy_tunnel`](struct.Easy2.html#method.http_proxy_tunnel) + pub fn http_proxy_tunnel(&mut self, tunnel: bool) -> Result<(), Error> { + self.inner.http_proxy_tunnel(tunnel) + } + + /// Same as [`Easy2::interface`](struct.Easy2.html#method.interface) + pub fn interface(&mut self, interface: &str) -> Result<(), Error> { + self.inner.interface(interface) + } + + /// Same as [`Easy2::set_local_port`](struct.Easy2.html#method.set_local_port) + pub fn set_local_port(&mut self, port: u16) -> Result<(), Error> { + self.inner.set_local_port(port) + } + + /// Same as [`Easy2::local_port_range`](struct.Easy2.html#method.local_port_range) + pub fn local_port_range(&mut self, range: u16) -> Result<(), Error> { + self.inner.local_port_range(range) + } + + /// Same as [`Easy2::dns_cache_timeout`](struct.Easy2.html#method.dns_cache_timeout) + pub fn dns_cache_timeout(&mut self, dur: Duration) -> Result<(), Error> { + self.inner.dns_cache_timeout(dur) + } + + /// Same as [`Easy2::buffer_size`](struct.Easy2.html#method.buffer_size) + pub fn buffer_size(&mut self, size: usize) -> Result<(), Error> { + self.inner.buffer_size(size) + } + + /// Same as [`Easy2::tcp_nodelay`](struct.Easy2.html#method.tcp_nodelay) + pub fn tcp_nodelay(&mut self, enable: bool) -> Result<(), Error> { + self.inner.tcp_nodelay(enable) + } + + /// Same as [`Easy2::tcp_keepalive`](struct.Easy2.html#method.tcp_keepalive) + pub fn tcp_keepalive(&mut self, enable: bool) -> Result<(), Error> { + self.inner.tcp_keepalive(enable) + } + + /// Same as [`Easy2::tcp_keepintvl`](struct.Easy2.html#method.tcp_keepalive) + pub fn tcp_keepintvl(&mut self, dur: Duration) -> Result<(), Error> { + self.inner.tcp_keepintvl(dur) + } + + /// Same as [`Easy2::tcp_keepidle`](struct.Easy2.html#method.tcp_keepidle) + pub fn tcp_keepidle(&mut self, dur: Duration) -> Result<(), Error> { + self.inner.tcp_keepidle(dur) + } + + /// Same as [`Easy2::address_scope`](struct.Easy2.html#method.address_scope) + pub fn address_scope(&mut self, scope: u32) -> Result<(), Error> { + self.inner.address_scope(scope) + } + + // ========================================================================= + // Names and passwords + + /// Same as [`Easy2::username`](struct.Easy2.html#method.username) + pub fn username(&mut self, user: &str) -> Result<(), Error> { + self.inner.username(user) + } + + /// Same as [`Easy2::password`](struct.Easy2.html#method.password) + pub fn password(&mut self, pass: &str) -> Result<(), Error> { + self.inner.password(pass) + } + + /// Same as [`Easy2::http_auth`](struct.Easy2.html#method.http_auth) + pub fn http_auth(&mut self, auth: &Auth) -> Result<(), Error> { + self.inner.http_auth(auth) + } + + /// Same as [`Easy2::proxy_username`](struct.Easy2.html#method.proxy_username) + pub fn proxy_username(&mut self, user: &str) -> Result<(), Error> { + self.inner.proxy_username(user) + } + + /// Same as [`Easy2::proxy_password`](struct.Easy2.html#method.proxy_password) + pub fn proxy_password(&mut self, pass: &str) -> Result<(), Error> { + self.inner.proxy_password(pass) + } + + /// Same as [`Easy2::proxy_auth`](struct.Easy2.html#method.proxy_auth) + pub fn proxy_auth(&mut self, auth: &Auth) -> Result<(), Error> { + self.inner.proxy_auth(auth) + } + + /// Same as [`Easy2::netrc`](struct.Easy2.html#method.netrc) + pub fn netrc(&mut self, netrc: NetRc) -> Result<(), Error> { + self.inner.netrc(netrc) + } + + // ========================================================================= + // HTTP Options + + /// Same as [`Easy2::autoreferer`](struct.Easy2.html#method.autoreferer) + pub fn autoreferer(&mut self, enable: bool) -> Result<(), Error> { + self.inner.autoreferer(enable) + } + + /// Same as [`Easy2::accept_encoding`](struct.Easy2.html#method.accept_encoding) + pub fn accept_encoding(&mut self, encoding: &str) -> Result<(), Error> { + self.inner.accept_encoding(encoding) + } + + /// Same as [`Easy2::transfer_encoding`](struct.Easy2.html#method.transfer_encoding) + pub fn transfer_encoding(&mut self, enable: bool) -> Result<(), Error> { + self.inner.transfer_encoding(enable) + } + + /// Same as [`Easy2::follow_location`](struct.Easy2.html#method.follow_location) + pub fn follow_location(&mut self, enable: bool) -> Result<(), Error> { + self.inner.follow_location(enable) + } + + /// Same as [`Easy2::unrestricted_auth`](struct.Easy2.html#method.unrestricted_auth) + pub fn unrestricted_auth(&mut self, enable: bool) -> Result<(), Error> { + self.inner.unrestricted_auth(enable) + } + + /// Same as [`Easy2::max_redirections`](struct.Easy2.html#method.max_redirections) + pub fn max_redirections(&mut self, max: u32) -> Result<(), Error> { + self.inner.max_redirections(max) + } + + /// Same as [`Easy2::put`](struct.Easy2.html#method.put) + pub fn put(&mut self, enable: bool) -> Result<(), Error> { + self.inner.put(enable) + } + + /// Same as [`Easy2::post`](struct.Easy2.html#method.post) + pub fn post(&mut self, enable: bool) -> Result<(), Error> { + self.inner.post(enable) + } + + /// Same as [`Easy2::post_field_copy`](struct.Easy2.html#method.post_field_copy) + pub fn post_fields_copy(&mut self, data: &[u8]) -> Result<(), Error> { + self.inner.post_fields_copy(data) + } + + /// Same as [`Easy2::post_field_size`](struct.Easy2.html#method.post_field_size) + pub fn post_field_size(&mut self, size: u64) -> Result<(), Error> { + self.inner.post_field_size(size) + } + + /// Same as [`Easy2::httppost`](struct.Easy2.html#method.httppost) + pub fn httppost(&mut self, form: Form) -> Result<(), Error> { + self.inner.httppost(form) + } + + /// Same as [`Easy2::referer`](struct.Easy2.html#method.referer) + pub fn referer(&mut self, referer: &str) -> Result<(), Error> { + self.inner.referer(referer) + } + + /// Same as [`Easy2::useragent`](struct.Easy2.html#method.useragent) + pub fn useragent(&mut self, useragent: &str) -> Result<(), Error> { + self.inner.useragent(useragent) + } + + /// Same as [`Easy2::http_headers`](struct.Easy2.html#method.http_headers) + pub fn http_headers(&mut self, list: List) -> Result<(), Error> { + self.inner.http_headers(list) + } + + /// Same as [`Easy2::cookie`](struct.Easy2.html#method.cookie) + pub fn cookie(&mut self, cookie: &str) -> Result<(), Error> { + self.inner.cookie(cookie) + } + + /// Same as [`Easy2::cookie_file`](struct.Easy2.html#method.cookie_file) + pub fn cookie_file>(&mut self, file: P) -> Result<(), Error> { + self.inner.cookie_file(file) + } + + /// Same as [`Easy2::cookie_jar`](struct.Easy2.html#method.cookie_jar) + pub fn cookie_jar>(&mut self, file: P) -> Result<(), Error> { + self.inner.cookie_jar(file) + } + + /// Same as [`Easy2::cookie_session`](struct.Easy2.html#method.cookie_session) + pub fn cookie_session(&mut self, session: bool) -> Result<(), Error> { + self.inner.cookie_session(session) + } + + /// Same as [`Easy2::cookie_list`](struct.Easy2.html#method.cookie_list) + pub fn cookie_list(&mut self, cookie: &str) -> Result<(), Error> { + self.inner.cookie_list(cookie) + } + + /// Same as [`Easy2::get`](struct.Easy2.html#method.get) + pub fn get(&mut self, enable: bool) -> Result<(), Error> { + self.inner.get(enable) + } + + /// Same as [`Easy2::ignore_content_length`](struct.Easy2.html#method.ignore_content_length) + pub fn ignore_content_length(&mut self, ignore: bool) -> Result<(), Error> { + self.inner.ignore_content_length(ignore) + } + + /// Same as [`Easy2::http_content_decoding`](struct.Easy2.html#method.http_content_decoding) + pub fn http_content_decoding(&mut self, enable: bool) -> Result<(), Error> { + self.inner.http_content_decoding(enable) + } + + /// Same as [`Easy2::http_transfer_decoding`](struct.Easy2.html#method.http_transfer_decoding) + pub fn http_transfer_decoding(&mut self, enable: bool) -> Result<(), Error> { + self.inner.http_transfer_decoding(enable) + } + + // ========================================================================= + // Protocol Options + + /// Same as [`Easy2::range`](struct.Easy2.html#method.range) + pub fn range(&mut self, range: &str) -> Result<(), Error> { + self.inner.range(range) + } + + /// Same as [`Easy2::resume_from`](struct.Easy2.html#method.resume_from) + pub fn resume_from(&mut self, from: u64) -> Result<(), Error> { + self.inner.resume_from(from) + } + + /// Same as [`Easy2::custom_request`](struct.Easy2.html#method.custom_request) + pub fn custom_request(&mut self, request: &str) -> Result<(), Error> { + self.inner.custom_request(request) + } + + /// Same as [`Easy2::fetch_filetime`](struct.Easy2.html#method.fetch_filetime) + pub fn fetch_filetime(&mut self, fetch: bool) -> Result<(), Error> { + self.inner.fetch_filetime(fetch) + } + + /// Same as [`Easy2::nobody`](struct.Easy2.html#method.nobody) + pub fn nobody(&mut self, enable: bool) -> Result<(), Error> { + self.inner.nobody(enable) + } + + /// Same as [`Easy2::in_filesize`](struct.Easy2.html#method.in_filesize) + pub fn in_filesize(&mut self, size: u64) -> Result<(), Error> { + self.inner.in_filesize(size) + } + + /// Same as [`Easy2::upload`](struct.Easy2.html#method.upload) + pub fn upload(&mut self, enable: bool) -> Result<(), Error> { + self.inner.upload(enable) + } + + /// Same as [`Easy2::max_filesize`](struct.Easy2.html#method.max_filesize) + pub fn max_filesize(&mut self, size: u64) -> Result<(), Error> { + self.inner.max_filesize(size) + } + + /// Same as [`Easy2::time_condition`](struct.Easy2.html#method.time_condition) + pub fn time_condition(&mut self, cond: TimeCondition) -> Result<(), Error> { + self.inner.time_condition(cond) + } + + /// Same as [`Easy2::time_value`](struct.Easy2.html#method.time_value) + pub fn time_value(&mut self, val: i64) -> Result<(), Error> { + self.inner.time_value(val) + } + + // ========================================================================= + // Connection Options + + /// Same as [`Easy2::timeout`](struct.Easy2.html#method.timeout) + pub fn timeout(&mut self, timeout: Duration) -> Result<(), Error> { + self.inner.timeout(timeout) + } + + /// Same as [`Easy2::low_speed_limit`](struct.Easy2.html#method.low_speed_limit) + pub fn low_speed_limit(&mut self, limit: u32) -> Result<(), Error> { + self.inner.low_speed_limit(limit) + } + + /// Same as [`Easy2::low_speed_time`](struct.Easy2.html#method.low_speed_time) + pub fn low_speed_time(&mut self, dur: Duration) -> Result<(), Error> { + self.inner.low_speed_time(dur) + } + + /// Same as [`Easy2::max_send_speed`](struct.Easy2.html#method.max_send_speed) + pub fn max_send_speed(&mut self, speed: u64) -> Result<(), Error> { + self.inner.max_send_speed(speed) + } + + /// Same as [`Easy2::max_recv_speed`](struct.Easy2.html#method.max_recv_speed) + pub fn max_recv_speed(&mut self, speed: u64) -> Result<(), Error> { + self.inner.max_recv_speed(speed) + } + + /// Same as [`Easy2::max_connects`](struct.Easy2.html#method.max_connects) + pub fn max_connects(&mut self, max: u32) -> Result<(), Error> { + self.inner.max_connects(max) + } + + /// Same as [`Easy2::fresh_connect`](struct.Easy2.html#method.fresh_connect) + pub fn fresh_connect(&mut self, enable: bool) -> Result<(), Error> { + self.inner.fresh_connect(enable) + } + + /// Same as [`Easy2::forbid_reuse`](struct.Easy2.html#method.forbid_reuse) + pub fn forbid_reuse(&mut self, enable: bool) -> Result<(), Error> { + self.inner.forbid_reuse(enable) + } + + /// Same as [`Easy2::connect_timeout`](struct.Easy2.html#method.connect_timeout) + pub fn connect_timeout(&mut self, timeout: Duration) -> Result<(), Error> { + self.inner.connect_timeout(timeout) + } + + /// Same as [`Easy2::ip_resolve`](struct.Easy2.html#method.ip_resolve) + pub fn ip_resolve(&mut self, resolve: IpResolve) -> Result<(), Error> { + self.inner.ip_resolve(resolve) + } + + /// Same as [`Easy2::resolve`](struct.Easy2.html#method.resolve) + pub fn resolve(&mut self, list: List) -> Result<(), Error> { + self.inner.resolve(list) + } + + /// Same as [`Easy2::connect_only`](struct.Easy2.html#method.connect_only) + pub fn connect_only(&mut self, enable: bool) -> Result<(), Error> { + self.inner.connect_only(enable) + } + + // ========================================================================= + // SSL/Security Options + + /// Same as [`Easy2::ssl_cert`](struct.Easy2.html#method.ssl_cert) + pub fn ssl_cert>(&mut self, cert: P) -> Result<(), Error> { + self.inner.ssl_cert(cert) + } + + /// Same as [`Easy2::ssl_cert_type`](struct.Easy2.html#method.ssl_cert_type) + pub fn ssl_cert_type(&mut self, kind: &str) -> Result<(), Error> { + self.inner.ssl_cert_type(kind) + } + + /// Same as [`Easy2::ssl_key`](struct.Easy2.html#method.ssl_key) + pub fn ssl_key>(&mut self, key: P) -> Result<(), Error> { + self.inner.ssl_key(key) + } + + /// Same as [`Easy2::ssl_key_type`](struct.Easy2.html#method.ssl_key_type) + pub fn ssl_key_type(&mut self, kind: &str) -> Result<(), Error> { + self.inner.ssl_key_type(kind) + } + + /// Same as [`Easy2::key_password`](struct.Easy2.html#method.key_password) + pub fn key_password(&mut self, password: &str) -> Result<(), Error> { + self.inner.key_password(password) + } + + /// Same as [`Easy2::ssl_engine`](struct.Easy2.html#method.ssl_engine) + pub fn ssl_engine(&mut self, engine: &str) -> Result<(), Error> { + self.inner.ssl_engine(engine) + } + + /// Same as [`Easy2::ssl_engine_default`](struct.Easy2.html#method.ssl_engine_default) + pub fn ssl_engine_default(&mut self, enable: bool) -> Result<(), Error> { + self.inner.ssl_engine_default(enable) + } + + /// Same as [`Easy2::http_version`](struct.Easy2.html#method.http_version) + pub fn http_version(&mut self, version: HttpVersion) -> Result<(), Error> { + self.inner.http_version(version) + } + + /// Same as [`Easy2::ssl_version`](struct.Easy2.html#method.ssl_version) + pub fn ssl_version(&mut self, version: SslVersion) -> Result<(), Error> { + self.inner.ssl_version(version) + } + + /// Same as [`Easy2::ssl_verify_host`](struct.Easy2.html#method.ssl_verify_host) + pub fn ssl_verify_host(&mut self, verify: bool) -> Result<(), Error> { + self.inner.ssl_verify_host(verify) + } + + /// Same as [`Easy2::ssl_verify_peer`](struct.Easy2.html#method.ssl_verify_peer) + pub fn ssl_verify_peer(&mut self, verify: bool) -> Result<(), Error> { + self.inner.ssl_verify_peer(verify) + } + + /// Same as [`Easy2::cainfo`](struct.Easy2.html#method.cainfo) + pub fn cainfo>(&mut self, path: P) -> Result<(), Error> { + self.inner.cainfo(path) + } + + /// Same as [`Easy2::issuer_cert`](struct.Easy2.html#method.issuer_cert) + pub fn issuer_cert>(&mut self, path: P) -> Result<(), Error> { + self.inner.issuer_cert(path) + } + + /// Same as [`Easy2::capath`](struct.Easy2.html#method.capath) + pub fn capath>(&mut self, path: P) -> Result<(), Error> { + self.inner.capath(path) + } + + /// Same as [`Easy2::crlfile`](struct.Easy2.html#method.crlfile) + pub fn crlfile>(&mut self, path: P) -> Result<(), Error> { + self.inner.crlfile(path) + } + + /// Same as [`Easy2::certinfo`](struct.Easy2.html#method.certinfo) + pub fn certinfo(&mut self, enable: bool) -> Result<(), Error> { + self.inner.certinfo(enable) + } + + /// Same as [`Easy2::random_file`](struct.Easy2.html#method.random_file) + pub fn random_file>(&mut self, p: P) -> Result<(), Error> { + self.inner.random_file(p) + } + + /// Same as [`Easy2::egd_socket`](struct.Easy2.html#method.egd_socket) + pub fn egd_socket>(&mut self, p: P) -> Result<(), Error> { + self.inner.egd_socket(p) + } + + /// Same as [`Easy2::ssl_cipher_list`](struct.Easy2.html#method.ssl_cipher_list) + pub fn ssl_cipher_list(&mut self, ciphers: &str) -> Result<(), Error> { + self.inner.ssl_cipher_list(ciphers) + } + + /// Same as [`Easy2::ssl_sessionid_cache`](struct.Easy2.html#method.ssl_sessionid_cache) + pub fn ssl_sessionid_cache(&mut self, enable: bool) -> Result<(), Error> { + self.inner.ssl_sessionid_cache(enable) + } + + /// Same as [`Easy2::ssl_options`](struct.Easy2.html#method.ssl_options) + pub fn ssl_options(&mut self, bits: &SslOpt) -> Result<(), Error> { + self.inner.ssl_options(bits) + } + + // ========================================================================= + // getters + + /// Same as [`Easy2::effective_url`](struct.Easy2.html#method.effective_url) + pub fn effective_url(&mut self) -> Result, Error> { + self.inner.effective_url() + } + + /// Same as [`Easy2::effective_url_bytes`](struct.Easy2.html#method.effective_url_bytes) + pub fn effective_url_bytes(&mut self) -> Result, Error> { + self.inner.effective_url_bytes() + } + + /// Same as [`Easy2::response_code`](struct.Easy2.html#method.response_code) + pub fn response_code(&mut self) -> Result { + self.inner.response_code() + } + + /// Same as [`Easy2::http_connectcode`](struct.Easy2.html#method.http_connectcode) + pub fn http_connectcode(&mut self) -> Result { + self.inner.http_connectcode() + } + + /// Same as [`Easy2::filetime`](struct.Easy2.html#method.filetime) + pub fn filetime(&mut self) -> Result, Error> { + self.inner.filetime() + } + + /// Same as [`Easy2::total_time`](struct.Easy2.html#method.total_time) + pub fn total_time(&mut self) -> Result { + self.inner.total_time() + } + + /// Same as [`Easy2::namelookup_time`](struct.Easy2.html#method.namelookup_time) + pub fn namelookup_time(&mut self) -> Result { + self.inner.namelookup_time() + } + + /// Same as [`Easy2::connect_time`](struct.Easy2.html#method.connect_time) + pub fn connect_time(&mut self) -> Result { + self.inner.connect_time() + } + + /// Same as [`Easy2::appconnect_time`](struct.Easy2.html#method.appconnect_time) + pub fn appconnect_time(&mut self) -> Result { + self.inner.appconnect_time() + } + + /// Same as [`Easy2::pretransfer_time`](struct.Easy2.html#method.pretransfer_time) + pub fn pretransfer_time(&mut self) -> Result { + self.inner.pretransfer_time() + } + + /// Same as [`Easy2::starttransfer_time`](struct.Easy2.html#method.starttransfer_time) + pub fn starttransfer_time(&mut self) -> Result { + self.inner.starttransfer_time() + } + + /// Same as [`Easy2::redirect_time`](struct.Easy2.html#method.redirect_time) + pub fn redirect_time(&mut self) -> Result { + self.inner.redirect_time() + } + + /// Same as [`Easy2::redirect_count`](struct.Easy2.html#method.redirect_count) + pub fn redirect_count(&mut self) -> Result { + self.inner.redirect_count() + } + + /// Same as [`Easy2::redirect_url`](struct.Easy2.html#method.redirect_url) + pub fn redirect_url(&mut self) -> Result, Error> { + self.inner.redirect_url() + } + + /// Same as [`Easy2::redirect_url_bytes`](struct.Easy2.html#method.redirect_url_bytes) + pub fn redirect_url_bytes(&mut self) -> Result, Error> { + self.inner.redirect_url_bytes() + } + + /// Same as [`Easy2::header_size`](struct.Easy2.html#method.header_size) + pub fn header_size(&mut self) -> Result { + self.inner.header_size() + } + + /// Same as [`Easy2::request_size`](struct.Easy2.html#method.request_size) + pub fn request_size(&mut self) -> Result { + self.inner.request_size() + } + + /// Same as [`Easy2::content_type`](struct.Easy2.html#method.content_type) + pub fn content_type(&mut self) -> Result, Error> { + self.inner.content_type() + } + + /// Same as [`Easy2::content_type_bytes`](struct.Easy2.html#method.content_type_bytes) + pub fn content_type_bytes(&mut self) -> Result, Error> { + self.inner.content_type_bytes() + } + + /// Same as [`Easy2::os_errno`](struct.Easy2.html#method.os_errno) + pub fn os_errno(&mut self) -> Result { + self.inner.os_errno() + } + + /// Same as [`Easy2::primary_ip`](struct.Easy2.html#method.primary_ip) + pub fn primary_ip(&mut self) -> Result, Error> { + self.inner.primary_ip() + } + + /// Same as [`Easy2::primary_port`](struct.Easy2.html#method.primary_port) + pub fn primary_port(&mut self) -> Result { + self.inner.primary_port() + } + + /// Same as [`Easy2::local_ip`](struct.Easy2.html#method.local_ip) + pub fn local_ip(&mut self) -> Result, Error> { + self.inner.local_ip() + } + + /// Same as [`Easy2::local_port`](struct.Easy2.html#method.local_port) + pub fn local_port(&mut self) -> Result { + self.inner.local_port() + } + + /// Same as [`Easy2::cookies`](struct.Easy2.html#method.cookies) + pub fn cookies(&mut self) -> Result { + self.inner.cookies() + } + + // ========================================================================= + // Other methods + + /// Same as [`Easy2::perform`](struct.Easy2.html#method.perform) + pub fn perform(&self) -> Result<(), Error> { + assert!(self.inner.get_ref().borrowed.get().is_null()); + self.do_perform() + } + + fn do_perform(&self) -> Result<(), Error> { + // We don't allow recursive invocations of `perform` because we're + // invoking `FnMut`closures behind a `&self` pointer. This flag acts as + // our own `RefCell` borrow flag sorta. + if self.inner.get_ref().running.get() { + return Err(Error::new(curl_sys::CURLE_FAILED_INIT)) + } + + self.inner.get_ref().running.set(true); + struct Reset<'a>(&'a Cell); + impl<'a> Drop for Reset<'a> { + fn drop(&mut self) { + self.0.set(false); + } + } + let _reset = Reset(&self.inner.get_ref().running); + + self.inner.perform() + } + + /// Creates a new scoped transfer which can be used to set callbacks and + /// data which only live for the scope of the returned object. + /// + /// An `Easy` handle is often reused between different requests to cache + /// connections to servers, but often the lifetime of the data as part of + /// each transfer is unique. This function serves as an ability to share an + /// `Easy` across many transfers while ergonomically using possibly + /// stack-local data as part of each transfer. + /// + /// Configuration can be set on the `Easy` and then a `Transfer` can be + /// created to set scoped configuration (like callbacks). Finally, the + /// `perform` method on the `Transfer` function can be used. + /// + /// When the `Transfer` option is dropped then all configuration set on the + /// transfer itself will be reset. + pub fn transfer<'data, 'easy>(&'easy mut self) -> Transfer<'easy, 'data> { + assert!(!self.inner.get_ref().running.get()); + Transfer { + data: Box::new(Callbacks::default()), + easy: self, + } + } + + /// Same as [`Easy2::unpause_read`](struct.Easy2.html#method.unpause_read) + pub fn unpause_read(&self) -> Result<(), Error> { + self.inner.unpause_read() + } + + /// Same as [`Easy2::unpause_write`](struct.Easy2.html#method.unpause_write) + pub fn unpause_write(&self) -> Result<(), Error> { + self.inner.unpause_write() + } + + /// Same as [`Easy2::url_encode`](struct.Easy2.html#method.url_encode) + pub fn url_encode(&mut self, s: &[u8]) -> String { + self.inner.url_encode(s) + } + + /// Same as [`Easy2::url_decode`](struct.Easy2.html#method.url_decode) + pub fn url_decode(&mut self, s: &str) -> Vec { + self.inner.url_decode(s) + } + + /// Same as [`Easy2::reset`](struct.Easy2.html#method.reset) + pub fn reset(&mut self) { + self.inner.reset() + } + + /// Same as [`Easy2::recv`](struct.Easy2.html#method.recv) + pub fn recv(&mut self, data: &mut [u8]) -> Result { + self.inner.recv(data) + } + + /// Same as [`Easy2::send`](struct.Easy2.html#method.send) + pub fn send(&mut self, data: &[u8]) -> Result { + self.inner.send(data) + } + + /// Same as [`Easy2::raw`](struct.Easy2.html#method.raw) + pub fn raw(&self) -> *mut curl_sys::CURL { + self.inner.raw() + } +} + +impl EasyData { + /// An unsafe function to get the appropriate callback field. + /// + /// We can have callbacks configured from one of two different sources. + /// We could either have a callback from the `borrowed` field, callbacks on + /// an ephemeral `Transfer`, or the `owned` field which are `'static` + /// callbacks that live for the lifetime of this `EasyData`. + /// + /// The first set of callbacks are unsafe to access because they're actually + /// owned elsewhere and we're just aliasing. Additionally they don't + /// technically live long enough for us to access them, so they're hidden + /// behind unsafe pointers and casts. + /// + /// This function returns `&'a mut T` but that's actually somewhat of a lie. + /// The value should **not be stored to** nor should it be used for the full + /// lifetime of `'a`, but rather immediately in the local scope. + /// + /// Basically this is just intended to acquire a callback, invoke it, and + /// then stop. Nothing else. Super unsafe. + unsafe fn callback<'a, T, F>(&'a mut self, f: F) -> Option<&'a mut T> + where F: for<'b> Fn(&'b mut Callbacks<'static>) -> &'b mut Option, + { + let ptr = self.borrowed.get(); + if !ptr.is_null() { + let val = f(&mut *ptr); + if val.is_some() { + return val.as_mut() + } + } + f(&mut self.owned).as_mut() + } +} + +impl Handler for EasyData { + fn write(&mut self, data: &[u8]) -> Result { + unsafe { + match self.callback(|s| &mut s.write) { + Some(write) => write(data), + None => Ok(data.len()), + } + } + } + + fn read(&mut self, data: &mut [u8]) -> Result { + unsafe { + match self.callback(|s| &mut s.read) { + Some(read) => read(data), + None => Ok(0), + } + } + } + + fn seek(&mut self, whence: SeekFrom) -> SeekResult { + unsafe { + match self.callback(|s| &mut s.seek) { + Some(seek) => seek(whence), + None => SeekResult::CantSeek, + } + } + } + + fn debug(&mut self, kind: InfoType, data: &[u8]) { + unsafe { + match self.callback(|s| &mut s.debug) { + Some(debug) => debug(kind, data), + None => handler::debug(kind, data), + } + } + } + + fn header(&mut self, data: &[u8]) -> bool { + unsafe { + match self.callback(|s| &mut s.header) { + Some(header) => header(data), + None => true, + } + } + } + + fn progress(&mut self, + dltotal: f64, + dlnow: f64, + ultotal: f64, + ulnow: f64) -> bool { + unsafe { + match self.callback(|s| &mut s.progress) { + Some(progress) => progress(dltotal, dlnow, ultotal, ulnow), + None => true, + } + } + } + + fn ssl_ctx(&mut self, cx: *mut c_void) -> Result<(), Error> { + unsafe { + match self.callback(|s| &mut s.ssl_ctx) { + Some(ssl_ctx) => ssl_ctx(cx), + None => handler::ssl_ctx(cx), + } + } + } +} + +impl fmt::Debug for EasyData { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "callbacks ...".fmt(f) + } +} + +impl<'easy, 'data> Transfer<'easy, 'data> { + /// Same as `Easy::write_function`, just takes a non `'static` lifetime + /// corresponding to the lifetime of this transfer. + pub fn write_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(&[u8]) -> Result + 'data + { + self.data.write = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::read_function`, just takes a non `'static` lifetime + /// corresponding to the lifetime of this transfer. + pub fn read_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(&mut [u8]) -> Result + 'data + { + self.data.read = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::seek_function`, just takes a non `'static` lifetime + /// corresponding to the lifetime of this transfer. + pub fn seek_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(SeekFrom) -> SeekResult + 'data + { + self.data.seek = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::progress_function`, just takes a non `'static` lifetime + /// corresponding to the lifetime of this transfer. + pub fn progress_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(f64, f64, f64, f64) -> bool + 'data + { + self.data.progress = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::ssl_ctx_function`, just takes a non `'static` + /// lifetime corresponding to the lifetime of this transfer. + pub fn ssl_ctx_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(*mut c_void) -> Result<(), Error> + Send + 'data + { + self.data.ssl_ctx = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::debug_function`, just takes a non `'static` lifetime + /// corresponding to the lifetime of this transfer. + pub fn debug_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(InfoType, &[u8]) + 'data + { + self.data.debug = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::header_function`, just takes a non `'static` lifetime + /// corresponding to the lifetime of this transfer. + pub fn header_function(&mut self, f: F) -> Result<(), Error> + where F: FnMut(&[u8]) -> bool + 'data + { + self.data.header = Some(Box::new(f)); + Ok(()) + } + + /// Same as `Easy::transfer`. + pub fn perform(&self) -> Result<(), Error> { + let inner = self.easy.inner.get_ref(); + + // Note that we're casting a `&self` pointer to a `*mut`, and then + // during the invocation of this call we're going to invoke `FnMut` + // closures that we ourselves own. + // + // This should be ok, however, because `do_perform` checks for recursive + // invocations of `perform` and disallows them. Our type also isn't + // `Sync`. + inner.borrowed.set(&*self.data as *const _ as *mut _); + + // Make sure to reset everything back to the way it was before when + // we're done. + struct Reset<'a>(&'a Cell<*mut Callbacks<'static>>); + impl<'a> Drop for Reset<'a> { + fn drop(&mut self) { + self.0.set(ptr::null_mut()); + } + } + let _reset = Reset(&inner.borrowed); + + self.easy.do_perform() + } + + /// Same as `Easy::unpause_read`. + pub fn unpause_read(&self) -> Result<(), Error> { + self.easy.unpause_read() + } + + /// Same as `Easy::unpause_write` + pub fn unpause_write(&self) -> Result<(), Error> { + self.easy.unpause_write() + } +} + +impl<'easy, 'data> fmt::Debug for Transfer<'easy, 'data> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Transfer") + .field("easy", &self.easy) + .finish() + } +} + +impl<'easy, 'data> Drop for Transfer<'easy, 'data> { + fn drop(&mut self) { + // Extra double check to make sure we don't leak a pointer to ourselves. + assert!(self.easy.inner.get_ref().borrowed.get().is_null()); + } +} diff --git a/curl-0.4.11/src/easy/handler.rs b/curl-0.4.11/src/easy/handler.rs new file mode 100644 index 000000000..2eef3ee00 --- /dev/null +++ b/curl-0.4.11/src/easy/handler.rs @@ -0,0 +1,3142 @@ +use std::cell::RefCell; +use std::ffi::{CStr, CString}; +use std::fmt; +use std::io::{self, SeekFrom, Write}; +use std::path::Path; +use std::slice; +use std::str; +use std::time::Duration; + +use curl_sys; +use libc::{self, c_void, c_char, c_long, size_t, c_int, c_double, c_ulong}; +use socket2::Socket; + +use Error; +use easy::form; +use easy::list; +use easy::{List, Form}; +use easy::windows; +use panic; + +/// A trait for the various callbacks used by libcurl to invoke user code. +/// +/// This trait represents all operations that libcurl can possibly invoke a +/// client for code during an HTTP transaction. Each callback has a default +/// "noop" implementation, the same as in libcurl. Types implementing this trait +/// may simply override the relevant functions to learn about the callbacks +/// they're interested in. +/// +/// # Examples +/// +/// ``` +/// use curl::easy::{Easy2, Handler, WriteError}; +/// +/// struct Collector(Vec); +/// +/// impl Handler for Collector { +/// fn write(&mut self, data: &[u8]) -> Result { +/// self.0.extend_from_slice(data); +/// Ok(data.len()) +/// } +/// } +/// +/// let mut easy = Easy2::new(Collector(Vec::new())); +/// easy.get(true).unwrap(); +/// easy.url("https://www.rust-lang.org/").unwrap(); +/// easy.perform().unwrap(); +/// +/// assert_eq!(easy.response_code().unwrap(), 200); +/// let contents = easy.get_ref(); +/// println!("{}", String::from_utf8_lossy(&contents.0)); +/// ``` +pub trait Handler { + /// Callback invoked whenever curl has downloaded data for the application. + /// + /// This callback function gets called by libcurl as soon as there is data + /// received that needs to be saved. + /// + /// The callback function will be passed as much data as possible in all + /// invokes, but you must not make any assumptions. It may be one byte, it + /// may be thousands. If `show_header` is enabled, which makes header data + /// get passed to the write callback, you can get up to + /// `CURL_MAX_HTTP_HEADER` bytes of header data passed into it. This + /// usually means 100K. + /// + /// This function may be called with zero bytes data if the transferred file + /// is empty. + /// + /// The callback should return the number of bytes actually taken care of. + /// If that amount differs from the amount passed to your callback function, + /// it'll signal an error condition to the library. This will cause the + /// transfer to get aborted and the libcurl function used will return + /// an error with `is_write_error`. + /// + /// If your callback function returns `Err(WriteError::Pause)` it will cause + /// this transfer to become paused. See `unpause_write` for further details. + /// + /// By default data is sent into the void, and this corresponds to the + /// `CURLOPT_WRITEFUNCTION` and `CURLOPT_WRITEDATA` options. + fn write(&mut self, data: &[u8]) -> Result { + Ok(data.len()) + } + + /// Read callback for data uploads. + /// + /// This callback function gets called by libcurl as soon as it needs to + /// read data in order to send it to the peer - like if you ask it to upload + /// or post data to the server. + /// + /// Your function must then return the actual number of bytes that it stored + /// in that memory area. Returning 0 will signal end-of-file to the library + /// and cause it to stop the current transfer. + /// + /// If you stop the current transfer by returning 0 "pre-maturely" (i.e + /// before the server expected it, like when you've said you will upload N + /// bytes and you upload less than N bytes), you may experience that the + /// server "hangs" waiting for the rest of the data that won't come. + /// + /// The read callback may return `Err(ReadError::Abort)` to stop the + /// current operation immediately, resulting in a `is_aborted_by_callback` + /// error code from the transfer. + /// + /// The callback can return `Err(ReadError::Pause)` to cause reading from + /// this connection to pause. See `unpause_read` for further details. + /// + /// By default data not input, and this corresponds to the + /// `CURLOPT_READFUNCTION` and `CURLOPT_READDATA` options. + /// + /// Note that the lifetime bound on this function is `'static`, but that + /// is often too restrictive. To use stack data consider calling the + /// `transfer` method and then using `read_function` to configure a + /// callback that can reference stack-local data. + fn read(&mut self, data: &mut [u8]) -> Result { + drop(data); + Ok(0) + } + + /// User callback for seeking in input stream. + /// + /// This function gets called by libcurl to seek to a certain position in + /// the input stream and can be used to fast forward a file in a resumed + /// upload (instead of reading all uploaded bytes with the normal read + /// function/callback). It is also called to rewind a stream when data has + /// already been sent to the server and needs to be sent again. This may + /// happen when doing a HTTP PUT or POST with a multi-pass authentication + /// method, or when an existing HTTP connection is reused too late and the + /// server closes the connection. + /// + /// The callback function must return `SeekResult::Ok` on success, + /// `SeekResult::Fail` to cause the upload operation to fail or + /// `SeekResult::CantSeek` to indicate that while the seek failed, libcurl + /// is free to work around the problem if possible. The latter can sometimes + /// be done by instead reading from the input or similar. + /// + /// By default data this option is not set, and this corresponds to the + /// `CURLOPT_SEEKFUNCTION` and `CURLOPT_SEEKDATA` options. + fn seek(&mut self, whence: SeekFrom) -> SeekResult { + drop(whence); + SeekResult::CantSeek + } + + /// Specify a debug callback + /// + /// `debug_function` replaces the standard debug function used when + /// `verbose` is in effect. This callback receives debug information, + /// as specified in the type argument. + /// + /// By default this option is not set and corresponds to the + /// `CURLOPT_DEBUGFUNCTION` and `CURLOPT_DEBUGDATA` options. + fn debug(&mut self, kind: InfoType, data: &[u8]) { + debug(kind, data) + } + + /// Callback that receives header data + /// + /// This function gets called by libcurl as soon as it has received header + /// data. The header callback will be called once for each header and only + /// complete header lines are passed on to the callback. Parsing headers is + /// very easy using this. If this callback returns `false` it'll signal an + /// error to the library. This will cause the transfer to get aborted and + /// the libcurl function in progress will return `is_write_error`. + /// + /// A complete HTTP header that is passed to this function can be up to + /// CURL_MAX_HTTP_HEADER (100K) bytes. + /// + /// It's important to note that the callback will be invoked for the headers + /// of all responses received after initiating a request and not just the + /// final response. This includes all responses which occur during + /// authentication negotiation. If you need to operate on only the headers + /// from the final response, you will need to collect headers in the + /// callback yourself and use HTTP status lines, for example, to delimit + /// response boundaries. + /// + /// When a server sends a chunked encoded transfer, it may contain a + /// trailer. That trailer is identical to a HTTP header and if such a + /// trailer is received it is passed to the application using this callback + /// as well. There are several ways to detect it being a trailer and not an + /// ordinary header: 1) it comes after the response-body. 2) it comes after + /// the final header line (CR LF) 3) a Trailer: header among the regular + /// response-headers mention what header(s) to expect in the trailer. + /// + /// For non-HTTP protocols like FTP, POP3, IMAP and SMTP this function will + /// get called with the server responses to the commands that libcurl sends. + /// + /// By default this option is not set and corresponds to the + /// `CURLOPT_HEADERFUNCTION` and `CURLOPT_HEADERDATA` options. + fn header(&mut self, data: &[u8]) -> bool { + drop(data); + true + } + + /// Callback to progress meter function + /// + /// This function gets called by libcurl instead of its internal equivalent + /// with a frequent interval. While data is being transferred it will be + /// called very frequently, and during slow periods like when nothing is + /// being transferred it can slow down to about one call per second. + /// + /// The callback gets told how much data libcurl will transfer and has + /// transferred, in number of bytes. The first argument is the total number + /// of bytes libcurl expects to download in this transfer. The second + /// argument is the number of bytes downloaded so far. The third argument is + /// the total number of bytes libcurl expects to upload in this transfer. + /// The fourth argument is the number of bytes uploaded so far. + /// + /// Unknown/unused argument values passed to the callback will be set to + /// zero (like if you only download data, the upload size will remain 0). + /// Many times the callback will be called one or more times first, before + /// it knows the data sizes so a program must be made to handle that. + /// + /// Returning `false` from this callback will cause libcurl to abort the + /// transfer and return `is_aborted_by_callback`. + /// + /// If you transfer data with the multi interface, this function will not be + /// called during periods of idleness unless you call the appropriate + /// libcurl function that performs transfers. + /// + /// `progress` must be set to `true` to make this function actually get + /// called. + /// + /// By default this function calls an internal method and corresponds to + /// `CURLOPT_PROGRESSFUNCTION` and `CURLOPT_PROGRESSDATA`. + fn progress(&mut self, + dltotal: f64, + dlnow: f64, + ultotal: f64, + ulnow: f64) -> bool { + drop((dltotal, dlnow, ultotal, ulnow)); + true + } + + /// Callback to SSL context + /// + /// This callback function gets called by libcurl just before the + /// initialization of an SSL connection after having processed all + /// other SSL related options to give a last chance to an + /// application to modify the behaviour of the SSL + /// initialization. The `ssl_ctx` parameter is actually a pointer + /// to the SSL library's SSL_CTX. If an error is returned from the + /// callback no attempt to establish a connection is made and the + /// perform operation will return the callback's error code. + /// + /// This function will get called on all new connections made to a + /// server, during the SSL negotiation. The SSL_CTX pointer will + /// be a new one every time. + /// + /// To use this properly, a non-trivial amount of knowledge of + /// your SSL library is necessary. For example, you can use this + /// function to call library-specific callbacks to add additional + /// validation code for certificates, and even to change the + /// actual URI of a HTTPS request. + /// + /// By default this function calls an internal method and + /// corresponds to `CURLOPT_SSL_CTX_FUNCTION` and + /// `CURLOPT_SSL_CTX_DATA`. + /// + /// Note that this callback is not guaranteed to be called, not all versions + /// of libcurl support calling this callback. + fn ssl_ctx(&mut self, cx: *mut c_void) -> Result<(), Error> { + // By default, if we're on an OpenSSL enabled libcurl and we're on + // Windows, add the system's certificate store to OpenSSL's certificate + // store. + ssl_ctx(cx) + } + + /// Callback to open sockets for libcurl. + /// + /// This callback function gets called by libcurl instead of the socket(2) + /// call. The callback function should return the newly created socket + /// or `None` in case no connection could be established or another + /// error was detected. Any additional `setsockopt(2)` calls can of course + /// be done on the socket at the user's discretion. A `None` return + /// value from the callback function will signal an unrecoverable error to + /// libcurl and it will return `is_couldnt_connect` from the function that + /// triggered this callback. + /// + /// By default this function opens a standard socket and + /// corresponds to `CURLOPT_OPENSOCKETFUNCTION `. + fn open_socket(&mut self, + family: c_int, + socktype: c_int, + protocol: c_int) -> Option { + // Note that we override this to calling a function in `socket2` to + // ensure that we open all sockets with CLOEXEC. Otherwise if we rely on + // libcurl to open sockets it won't use CLOEXEC. + return Socket::new(family.into(), socktype.into(), Some(protocol.into())) + .ok() + .map(cvt); + + #[cfg(unix)] + fn cvt(socket: Socket) -> curl_sys::curl_socket_t { + use std::os::unix::prelude::*; + socket.into_raw_fd() + } + + #[cfg(windows)] + fn cvt(socket: Socket) -> curl_sys::curl_socket_t { + use std::os::windows::prelude::*; + socket.into_raw_socket() + } + } +} + +pub fn debug(kind: InfoType, data: &[u8]) { + let out = io::stderr(); + let prefix = match kind { + InfoType::Text => "*", + InfoType::HeaderIn => "<", + InfoType::HeaderOut => ">", + InfoType::DataIn | + InfoType::SslDataIn => "{", + InfoType::DataOut | + InfoType::SslDataOut => "}", + InfoType::__Nonexhaustive => " ", + }; + let mut out = out.lock(); + drop(write!(out, "{} ", prefix)); + drop(out.write_all(data)); +} + +pub fn ssl_ctx(cx: *mut c_void) -> Result<(), Error> { + windows::add_certs_to_context(cx); + Ok(()) +} + +/// Raw bindings to a libcurl "easy session". +/// +/// This type corresponds to the `CURL` type in libcurl, and is probably what +/// you want for just sending off a simple HTTP request and fetching a response. +/// Each easy handle can be thought of as a large builder before calling the +/// final `perform` function. +/// +/// There are many many configuration options for each `Easy2` handle, and they +/// should all have their own documentation indicating what it affects and how +/// it interacts with other options. Some implementations of libcurl can use +/// this handle to interact with many different protocols, although by default +/// this crate only guarantees the HTTP/HTTPS protocols working. +/// +/// Note that almost all methods on this structure which configure various +/// properties return a `Result`. This is largely used to detect whether the +/// underlying implementation of libcurl actually implements the option being +/// requested. If you're linked to a version of libcurl which doesn't support +/// the option, then an error will be returned. Some options also perform some +/// validation when they're set, and the error is returned through this vector. +/// +/// Note that historically this library contained an `Easy` handle so this one's +/// called `Easy2`. The major difference between the `Easy` type is that an +/// `Easy2` structure uses a trait instead of closures for all of the callbacks +/// that curl can invoke. The `Easy` type is actually built on top of this +/// `Easy` type, and this `Easy2` type can be more flexible in some situations +/// due to the generic parameter. +/// +/// There's not necessarily a right answer for which type is correct to use, but +/// as a general rule of thumb `Easy` is typically a reasonable choice for +/// synchronous I/O and `Easy2` is a good choice for asynchronous I/O. +/// +/// # Examples +/// +/// ``` +/// use curl::easy::{Easy2, Handler, WriteError}; +/// +/// struct Collector(Vec); +/// +/// impl Handler for Collector { +/// fn write(&mut self, data: &[u8]) -> Result { +/// self.0.extend_from_slice(data); +/// Ok(data.len()) +/// } +/// } +/// +/// let mut easy = Easy2::new(Collector(Vec::new())); +/// easy.get(true).unwrap(); +/// easy.url("https://www.rust-lang.org/").unwrap(); +/// easy.perform().unwrap(); +/// +/// assert_eq!(easy.response_code().unwrap(), 200); +/// let contents = easy.get_ref(); +/// println!("{}", String::from_utf8_lossy(&contents.0)); +/// ``` +pub struct Easy2 { + inner: Box>, +} + +struct Inner { + handle: *mut curl_sys::CURL, + header_list: Option, + resolve_list: Option, + form: Option

, + error_buf: RefCell>, + handler: H, +} + +unsafe impl Send for Inner {} + +/// Possible proxy types that libcurl currently understands. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum ProxyType { + Http = curl_sys::CURLPROXY_HTTP as isize, + Http1 = curl_sys::CURLPROXY_HTTP_1_0 as isize, + Socks4 = curl_sys::CURLPROXY_SOCKS4 as isize, + Socks5 = curl_sys::CURLPROXY_SOCKS5 as isize, + Socks4a = curl_sys::CURLPROXY_SOCKS4A as isize, + Socks5Hostname = curl_sys::CURLPROXY_SOCKS5_HOSTNAME as isize, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive, +} + +/// Possible conditions for the `time_condition` method. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum TimeCondition { + None = curl_sys::CURL_TIMECOND_NONE as isize, + IfModifiedSince = curl_sys::CURL_TIMECOND_IFMODSINCE as isize, + IfUnmodifiedSince = curl_sys::CURL_TIMECOND_IFUNMODSINCE as isize, + LastModified = curl_sys::CURL_TIMECOND_LASTMOD as isize, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive, +} + +/// Possible values to pass to the `ip_resolve` method. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum IpResolve { + V4 = curl_sys::CURL_IPRESOLVE_V4 as isize, + V6 = curl_sys::CURL_IPRESOLVE_V6 as isize, + Any = curl_sys::CURL_IPRESOLVE_WHATEVER as isize, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive = 500, +} + +/// Possible values to pass to the `http_version` method. +#[derive(Debug)] +pub enum HttpVersion { + /// We don't care what http version to use, and we'd like the library to + /// choose the best possible for us. + Any = curl_sys::CURL_HTTP_VERSION_NONE as isize, + + /// Please use HTTP 1.0 in the request + V10 = curl_sys::CURL_HTTP_VERSION_1_0 as isize, + + /// Please use HTTP 1.1 in the request + V11 = curl_sys::CURL_HTTP_VERSION_1_1 as isize, + + /// Please use HTTP 2 in the request + /// (Added in CURL 7.33.0) + V2 = curl_sys::CURL_HTTP_VERSION_2_0 as isize, + + /// Use version 2 for HTTPS, version 1.1 for HTTP + /// (Added in CURL 7.47.0) + V2TLS = curl_sys::CURL_HTTP_VERSION_2TLS as isize, + + /// Please use HTTP 2 without HTTP/1.1 Upgrade + /// (Added in CURL 7.49.0) + V2PriorKnowledge = curl_sys::CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE as isize, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive = 500, +} + +/// Possible values to pass to the `ip_resolve` method. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum SslVersion { + Default = curl_sys::CURL_SSLVERSION_DEFAULT as isize, + Tlsv1 = curl_sys::CURL_SSLVERSION_TLSv1 as isize, + Sslv2 = curl_sys::CURL_SSLVERSION_SSLv2 as isize, + Sslv3 = curl_sys::CURL_SSLVERSION_SSLv3 as isize, + // Tlsv10 = curl_sys::CURL_SSLVERSION_TLSv1_0 as isize, + // Tlsv11 = curl_sys::CURL_SSLVERSION_TLSv1_1 as isize, + // Tlsv12 = curl_sys::CURL_SSLVERSION_TLSv1_2 as isize, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive = 500, +} + +/// Possible return values from the `seek_function` callback. +#[derive(Debug)] +pub enum SeekResult { + /// Indicates that the seek operation was a success + Ok = curl_sys::CURL_SEEKFUNC_OK as isize, + + /// Indicates that the seek operation failed, and the entire request should + /// fail as a result. + Fail = curl_sys::CURL_SEEKFUNC_FAIL as isize, + + /// Indicates that although the seek failed libcurl should attempt to keep + /// working if possible (for example "seek" through reading). + CantSeek = curl_sys::CURL_SEEKFUNC_CANTSEEK as isize, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive = 500, +} + +/// Possible data chunks that can be witnessed as part of the `debug_function` +/// callback. +#[derive(Debug)] +pub enum InfoType { + /// The data is informational text. + Text, + + /// The data is header (or header-like) data received from the peer. + HeaderIn, + + /// The data is header (or header-like) data sent to the peer. + HeaderOut, + + /// The data is protocol data received from the peer. + DataIn, + + /// The data is protocol data sent to the peer. + DataOut, + + /// The data is SSL/TLS (binary) data received from the peer. + SslDataIn, + + /// The data is SSL/TLS (binary) data sent to the peer. + SslDataOut, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive, +} + +/// Possible error codes that can be returned from the `read_function` callback. +#[derive(Debug)] +pub enum ReadError { + /// Indicates that the connection should be aborted immediately + Abort, + + /// Indicates that reading should be paused until `unpause` is called. + Pause, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive, +} + +/// Possible error codes that can be returned from the `write_function` callback. +#[derive(Debug)] +pub enum WriteError { + /// Indicates that reading should be paused until `unpause` is called. + Pause, + + /// Hidden variant to indicate that this enum should not be matched on, it + /// may grow over time. + #[doc(hidden)] + __Nonexhaustive, +} + +/// Options for `.netrc` parsing. +#[derive(Debug)] +pub enum NetRc { + /// Ignoring `.netrc` file and use information from url + /// + /// This option is default + Ignored = curl_sys::CURL_NETRC_IGNORED as isize, + + /// The use of your `~/.netrc` file is optional, and information in the URL is to be + /// preferred. The file will be scanned for the host and user name (to find the password only) + /// or for the host only, to find the first user name and password after that machine, which + /// ever information is not specified in the URL. + Optional = curl_sys::CURL_NETRC_OPTIONAL as isize, + + /// This value tells the library that use of the file is required, to ignore the information in + /// the URL, and to search the file for the host only. + Required = curl_sys::CURL_NETRC_REQUIRED as isize, +} + +/// Structure which stores possible authentication methods to get passed to +/// `http_auth` and `proxy_auth`. +#[derive(Clone)] +pub struct Auth { + bits: c_long, +} + +/// Structure which stores possible ssl options to pass to `ssl_options`. +#[derive(Clone)] +pub struct SslOpt { + bits: c_long, +} + +impl Easy2 { + /// Creates a new "easy" handle which is the core of almost all operations + /// in libcurl. + /// + /// To use a handle, applications typically configure a number of options + /// followed by a call to `perform`. Options are preserved across calls to + /// `perform` and need to be reset manually (or via the `reset` method) if + /// this is not desired. + pub fn new(handler: H) -> Easy2 { + ::init(); + unsafe { + let handle = curl_sys::curl_easy_init(); + assert!(!handle.is_null()); + let mut ret = Easy2 { + inner: Box::new(Inner { + handle: handle, + header_list: None, + resolve_list: None, + form: None, + error_buf: RefCell::new(vec![0; curl_sys::CURL_ERROR_SIZE]), + handler: handler, + }), + }; + ret.default_configure(); + return ret + } + } + + /// Re-initializes this handle to the default values. + /// + /// This puts the handle to the same state as it was in when it was just + /// created. This does, however, keep live connections, the session id + /// cache, the dns cache, and cookies. + pub fn reset(&mut self) { + unsafe { + curl_sys::curl_easy_reset(self.inner.handle); + } + self.default_configure(); + } + + fn default_configure(&mut self) { + self.setopt_ptr(curl_sys::CURLOPT_ERRORBUFFER, + self.inner.error_buf.borrow().as_ptr() as *const _) + .expect("failed to set error buffer"); + let _ = self.signal(false); + self.ssl_configure(); + + let ptr = &*self.inner as *const _ as *const _; + + let cb: extern fn(*mut c_char, size_t, size_t, *mut c_void) -> size_t + = header_cb::; + self.setopt_ptr(curl_sys::CURLOPT_HEADERFUNCTION, cb as *const _) + .expect("failed to set header callback"); + self.setopt_ptr(curl_sys::CURLOPT_HEADERDATA, ptr) + .expect("failed to set header callback"); + + let cb: curl_sys::curl_write_callback = write_cb::; + self.setopt_ptr(curl_sys::CURLOPT_WRITEFUNCTION, cb as *const _) + .expect("failed to set write callback"); + self.setopt_ptr(curl_sys::CURLOPT_WRITEDATA, ptr) + .expect("failed to set write callback"); + + let cb: curl_sys::curl_read_callback = read_cb::; + self.setopt_ptr(curl_sys::CURLOPT_READFUNCTION, cb as *const _) + .expect("failed to set read callback"); + self.setopt_ptr(curl_sys::CURLOPT_READDATA, ptr) + .expect("failed to set read callback"); + + let cb: curl_sys::curl_seek_callback = seek_cb::; + self.setopt_ptr(curl_sys::CURLOPT_SEEKFUNCTION, cb as *const _) + .expect("failed to set seek callback"); + self.setopt_ptr(curl_sys::CURLOPT_SEEKDATA, ptr) + .expect("failed to set seek callback"); + + let cb: curl_sys::curl_progress_callback = progress_cb::; + self.setopt_ptr(curl_sys::CURLOPT_PROGRESSFUNCTION, cb as *const _) + .expect("failed to set progress callback"); + self.setopt_ptr(curl_sys::CURLOPT_PROGRESSDATA, ptr) + .expect("failed to set progress callback"); + + let cb: curl_sys::curl_debug_callback = debug_cb::; + self.setopt_ptr(curl_sys::CURLOPT_DEBUGFUNCTION, cb as *const _) + .expect("failed to set debug callback"); + self.setopt_ptr(curl_sys::CURLOPT_DEBUGDATA, ptr) + .expect("failed to set debug callback"); + + let cb: curl_sys::curl_ssl_ctx_callback = ssl_ctx_cb::; + drop(self.setopt_ptr(curl_sys::CURLOPT_SSL_CTX_FUNCTION, cb as *const _)); + drop(self.setopt_ptr(curl_sys::CURLOPT_SSL_CTX_DATA, ptr)); + + let cb: curl_sys::curl_opensocket_callback = opensocket_cb::; + self.setopt_ptr(curl_sys::CURLOPT_OPENSOCKETFUNCTION , cb as *const _) + .expect("failed to set open socket callback"); + self.setopt_ptr(curl_sys::CURLOPT_OPENSOCKETDATA, ptr) + .expect("failed to set open socket callback"); + } + + #[cfg(all(unix, not(target_os = "macos")))] + fn ssl_configure(&mut self) { + let probe = ::openssl_probe::probe(); + if let Some(ref path) = probe.cert_file { + let _ = self.cainfo(path); + } + if let Some(ref path) = probe.cert_dir { + let _ = self.capath(path); + } + } + + #[cfg(not(all(unix, not(target_os = "macos"))))] + fn ssl_configure(&mut self) {} +} + +impl Easy2 { + // ========================================================================= + // Behavior options + + /// Configures this handle to have verbose output to help debug protocol + /// information. + /// + /// By default output goes to stderr, but the `stderr` function on this type + /// can configure that. You can also use the `debug_function` method to get + /// all protocol data sent and received. + /// + /// By default, this option is `false`. + pub fn verbose(&mut self, verbose: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_VERBOSE, verbose as c_long) + } + + /// Indicates whether header information is streamed to the output body of + /// this request. + /// + /// This option is only relevant for protocols which have header metadata + /// (like http or ftp). It's not generally possible to extract headers + /// from the body if using this method, that use case should be intended for + /// the `header_function` method. + /// + /// To set HTTP headers, use the `http_header` method. + /// + /// By default, this option is `false` and corresponds to + /// `CURLOPT_HEADER`. + pub fn show_header(&mut self, show: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HEADER, show as c_long) + } + + /// Indicates whether a progress meter will be shown for requests done with + /// this handle. + /// + /// This will also prevent the `progress_function` from being called. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_NOPROGRESS`. + pub fn progress(&mut self, progress: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_NOPROGRESS, + (!progress) as c_long) + } + + /// Inform libcurl whether or not it should install signal handlers or + /// attempt to use signals to perform library functions. + /// + /// If this option is disabled then timeouts during name resolution will not + /// work unless libcurl is built against c-ares. Note that enabling this + /// option, however, may not cause libcurl to work with multiple threads. + /// + /// By default this option is `false` and corresponds to `CURLOPT_NOSIGNAL`. + /// Note that this default is **different than libcurl** as it is intended + /// that this library is threadsafe by default. See the [libcurl docs] for + /// some more information. + /// + /// [libcurl docs]: https://curl.haxx.se/libcurl/c/threadsafe.html + pub fn signal(&mut self, signal: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_NOSIGNAL, + (!signal) as c_long) + } + + /// Indicates whether multiple files will be transferred based on the file + /// name pattern. + /// + /// The last part of a filename uses fnmatch-like pattern matching. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_WILDCARDMATCH`. + pub fn wildcard_match(&mut self, m: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_WILDCARDMATCH, m as c_long) + } + + /// Provides the unix domain socket which this handle will work with. + /// + /// The string provided must be unix domain socket -encoded with the format: + /// + /// ```text + /// /path/file.sock + /// ``` + pub fn unix_socket(&mut self, unix_domain_socket: &str) -> Result<(), Error> { + let socket = try!(CString::new(unix_domain_socket)); + self.setopt_str(curl_sys::CURLOPT_UNIX_SOCKET_PATH, &socket) + } + + + // ========================================================================= + // Internal accessors + + /// Acquires a reference to the underlying handler for events. + pub fn get_ref(&self) -> &H { + &self.inner.handler + } + + /// Acquires a reference to the underlying handler for events. + pub fn get_mut(&mut self) -> &mut H { + &mut self.inner.handler + } + + // ========================================================================= + // Error options + + // TODO: error buffer and stderr + + /// Indicates whether this library will fail on HTTP response codes >= 400. + /// + /// This method is not fail-safe especially when authentication is involved. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_FAILONERROR`. + pub fn fail_on_error(&mut self, fail: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_FAILONERROR, fail as c_long) + } + + // ========================================================================= + // Network options + + /// Provides the URL which this handle will work with. + /// + /// The string provided must be URL-encoded with the format: + /// + /// ```text + /// scheme://host:port/path + /// ``` + /// + /// The syntax is not validated as part of this function and that is + /// deferred until later. + /// + /// By default this option is not set and `perform` will not work until it + /// is set. This option corresponds to `CURLOPT_URL`. + pub fn url(&mut self, url: &str) -> Result<(), Error> { + let url = try!(CString::new(url)); + self.setopt_str(curl_sys::CURLOPT_URL, &url) + } + + /// Configures the port number to connect to, instead of the one specified + /// in the URL or the default of the protocol. + pub fn port(&mut self, port: u16) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_PORT, port as c_long) + } + + // /// Indicates whether sequences of `/../` and `/./` will be squashed or not. + // /// + // /// By default this option is `false` and corresponds to + // /// `CURLOPT_PATH_AS_IS`. + // pub fn path_as_is(&mut self, as_is: bool) -> Result<(), Error> { + // } + + /// Provide the URL of a proxy to use. + /// + /// By default this option is not set and corresponds to `CURLOPT_PROXY`. + pub fn proxy(&mut self, url: &str) -> Result<(), Error> { + let url = try!(CString::new(url)); + self.setopt_str(curl_sys::CURLOPT_PROXY, &url) + } + + /// Provide port number the proxy is listening on. + /// + /// By default this option is not set (the default port for the proxy + /// protocol is used) and corresponds to `CURLOPT_PROXYPORT`. + pub fn proxy_port(&mut self, port: u16) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_PROXYPORT, port as c_long) + } + + /// Indicates the type of proxy being used. + /// + /// By default this option is `ProxyType::Http` and corresponds to + /// `CURLOPT_PROXYTYPE`. + pub fn proxy_type(&mut self, kind: ProxyType) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_PROXYTYPE, kind as c_long) + } + + /// Provide a list of hosts that should not be proxied to. + /// + /// This string is a comma-separated list of hosts which should not use the + /// proxy specified for connections. A single `*` character is also accepted + /// as a wildcard for all hosts. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_NOPROXY`. + pub fn noproxy(&mut self, skip: &str) -> Result<(), Error> { + let skip = try!(CString::new(skip)); + self.setopt_str(curl_sys::CURLOPT_PROXYTYPE, &skip) + } + + /// Inform curl whether it should tunnel all operations through the proxy. + /// + /// This essentially means that a `CONNECT` is sent to the proxy for all + /// outbound requests. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_HTTPPROXYTUNNEL`. + pub fn http_proxy_tunnel(&mut self, tunnel: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HTTPPROXYTUNNEL, + tunnel as c_long) + } + + /// Tell curl which interface to bind to for an outgoing network interface. + /// + /// The interface name, IP address, or host name can be specified here. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_INTERFACE`. + pub fn interface(&mut self, interface: &str) -> Result<(), Error> { + let s = try!(CString::new(interface)); + self.setopt_str(curl_sys::CURLOPT_INTERFACE, &s) + } + + /// Indicate which port should be bound to locally for this connection. + /// + /// By default this option is 0 (any port) and corresponds to + /// `CURLOPT_LOCALPORT`. + pub fn set_local_port(&mut self, port: u16) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_LOCALPORT, port as c_long) + } + + /// Indicates the number of attempts libcurl will perform to find a working + /// port number. + /// + /// By default this option is 1 and corresponds to + /// `CURLOPT_LOCALPORTRANGE`. + pub fn local_port_range(&mut self, range: u16) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_LOCALPORTRANGE, + range as c_long) + } + + /// Sets the timeout of how long name resolves will be kept in memory. + /// + /// This is distinct from DNS TTL options and is entirely speculative. + /// + /// By default this option is 60s and corresponds to + /// `CURLOPT_DNS_CACHE_TIMEOUT`. + pub fn dns_cache_timeout(&mut self, dur: Duration) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_DNS_CACHE_TIMEOUT, + dur.as_secs() as c_long) + } + + /// Specify the preferred receive buffer size, in bytes. + /// + /// This is treated as a request, not an order, and the main point of this + /// is that the write callback may get called more often with smaller + /// chunks. + /// + /// By default this option is the maximum write size and corresopnds to + /// `CURLOPT_BUFFERSIZE`. + pub fn buffer_size(&mut self, size: usize) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_BUFFERSIZE, size as c_long) + } + + // /// Enable or disable TCP Fast Open + // /// + // /// By default this options defaults to `false` and corresponds to + // /// `CURLOPT_TCP_FASTOPEN` + // pub fn fast_open(&mut self, enable: bool) -> Result<(), Error> { + // } + + /// Configures whether the TCP_NODELAY option is set, or Nagle's algorithm + /// is disabled. + /// + /// The purpose of Nagle's algorithm is to minimize the number of small + /// packet's on the network, and disabling this may be less efficient in + /// some situations. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_TCP_NODELAY`. + pub fn tcp_nodelay(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TCP_NODELAY, enable as c_long) + } + + /// Configures whether TCP keepalive probes will be sent. + /// + /// The delay and frequency of these probes is controlled by `tcp_keepidle` + /// and `tcp_keepintvl`. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_TCP_KEEPALIVE`. + pub fn tcp_keepalive(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TCP_KEEPALIVE, enable as c_long) + } + + /// Configures the TCP keepalive idle time wait. + /// + /// This is the delay, after which the connection is idle, keepalive probes + /// will be sent. Not all operating systems support this. + /// + /// By default this corresponds to `CURLOPT_TCP_KEEPIDLE`. + pub fn tcp_keepidle(&mut self, amt: Duration) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TCP_KEEPIDLE, + amt.as_secs() as c_long) + } + + /// Configures the delay between keepalive probes. + /// + /// By default this corresponds to `CURLOPT_TCP_KEEPINTVL`. + pub fn tcp_keepintvl(&mut self, amt: Duration) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TCP_KEEPINTVL, + amt.as_secs() as c_long) + } + + /// Configures the scope for local IPv6 addresses. + /// + /// Sets the scope_id value to use when connecting to IPv6 or link-local + /// addresses. + /// + /// By default this value is 0 and corresponds to `CURLOPT_ADDRESS_SCOPE` + pub fn address_scope(&mut self, scope: u32) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_ADDRESS_SCOPE, + scope as c_long) + } + + // ========================================================================= + // Names and passwords + + /// Configures the username to pass as authentication for this connection. + /// + /// By default this value is not set and corresponds to `CURLOPT_USERNAME`. + pub fn username(&mut self, user: &str) -> Result<(), Error> { + let user = try!(CString::new(user)); + self.setopt_str(curl_sys::CURLOPT_USERNAME, &user) + } + + /// Configures the password to pass as authentication for this connection. + /// + /// By default this value is not set and corresponds to `CURLOPT_PASSWORD`. + pub fn password(&mut self, pass: &str) -> Result<(), Error> { + let pass = try!(CString::new(pass)); + self.setopt_str(curl_sys::CURLOPT_PASSWORD, &pass) + } + + /// Set HTTP server authentication methods to try + /// + /// If more than one method is set, libcurl will first query the site to see + /// which authentication methods it supports and then pick the best one you + /// allow it to use. For some methods, this will induce an extra network + /// round-trip. Set the actual name and password with the `password` and + /// `username` methods. + /// + /// For authentication with a proxy, see `proxy_auth`. + /// + /// By default this value is basic and corresponds to `CURLOPT_HTTPAUTH`. + pub fn http_auth(&mut self, auth: &Auth) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HTTPAUTH, auth.bits) + } + + /// Configures the proxy username to pass as authentication for this + /// connection. + /// + /// By default this value is not set and corresponds to + /// `CURLOPT_PROXYUSERNAME`. + pub fn proxy_username(&mut self, user: &str) -> Result<(), Error> { + let user = try!(CString::new(user)); + self.setopt_str(curl_sys::CURLOPT_PROXYUSERNAME, &user) + } + + /// Configures the proxy password to pass as authentication for this + /// connection. + /// + /// By default this value is not set and corresponds to + /// `CURLOPT_PROXYPASSWORD`. + pub fn proxy_password(&mut self, pass: &str) -> Result<(), Error> { + let pass = try!(CString::new(pass)); + self.setopt_str(curl_sys::CURLOPT_PROXYPASSWORD, &pass) + } + + /// Set HTTP proxy authentication methods to try + /// + /// If more than one method is set, libcurl will first query the site to see + /// which authentication methods it supports and then pick the best one you + /// allow it to use. For some methods, this will induce an extra network + /// round-trip. Set the actual name and password with the `proxy_password` + /// and `proxy_username` methods. + /// + /// By default this value is basic and corresponds to `CURLOPT_PROXYAUTH`. + pub fn proxy_auth(&mut self, auth: &Auth) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_PROXYAUTH, auth.bits) + } + + /// Enable .netrc parsing + /// + /// By default the .netrc file is ignored and corresponds to `CURL_NETRC_IGNORED`. + pub fn netrc(&mut self, netrc: NetRc) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_NETRC, netrc as c_long) + } + + // ========================================================================= + // HTTP Options + + /// Indicates whether the referer header is automatically updated + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_AUTOREFERER`. + pub fn autoreferer(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_AUTOREFERER, enable as c_long) + } + + /// Enables automatic decompression of HTTP downloads. + /// + /// Sets the contents of the Accept-Encoding header sent in an HTTP request. + /// This enables decoding of a response with Content-Encoding. + /// + /// Currently supported encoding are `identity`, `zlib`, and `gzip`. A + /// zero-length string passed in will send all accepted encodings. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_ACCEPT_ENCODING`. + pub fn accept_encoding(&mut self, encoding: &str) -> Result<(), Error> { + let encoding = try!(CString::new(encoding)); + self.setopt_str(curl_sys::CURLOPT_ACCEPT_ENCODING, &encoding) + } + + /// Request the HTTP Transfer Encoding. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_TRANSFER_ENCODING`. + pub fn transfer_encoding(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TRANSFER_ENCODING, enable as c_long) + } + + /// Follow HTTP 3xx redirects. + /// + /// Indicates whether any `Location` headers in the response should get + /// followed. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_FOLLOWLOCATION`. + pub fn follow_location(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_FOLLOWLOCATION, enable as c_long) + } + + /// Send credentials to hosts other than the first as well. + /// + /// Sends username/password credentials even when the host changes as part + /// of a redirect. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_UNRESTRICTED_AUTH`. + pub fn unrestricted_auth(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_UNRESTRICTED_AUTH, enable as c_long) + } + + /// Set the maximum number of redirects allowed. + /// + /// A value of 0 will refuse any redirect. + /// + /// By default this option is `-1` (unlimited) and corresponds to + /// `CURLOPT_MAXREDIRS`. + pub fn max_redirections(&mut self, max: u32) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_MAXREDIRS, max as c_long) + } + + // TODO: post_redirections + + /// Make an HTTP PUT request. + /// + /// By default this option is `false` and corresponds to `CURLOPT_PUT`. + pub fn put(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_PUT, enable as c_long) + } + + /// Make an HTTP POST request. + /// + /// This will also make the library use the + /// `Content-Type: application/x-www-form-urlencoded` header. + /// + /// POST data can be specified through `post_fields` or by specifying a read + /// function. + /// + /// By default this option is `false` and corresponds to `CURLOPT_POST`. + pub fn post(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_POST, enable as c_long) + } + + /// Configures the data that will be uploaded as part of a POST. + /// + /// Note that the data is copied into this handle and if that's not desired + /// then the read callbacks can be used instead. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_COPYPOSTFIELDS`. + pub fn post_fields_copy(&mut self, data: &[u8]) -> Result<(), Error> { + // Set the length before the pointer so libcurl knows how much to read + try!(self.post_field_size(data.len() as u64)); + self.setopt_ptr(curl_sys::CURLOPT_COPYPOSTFIELDS, + data.as_ptr() as *const _) + } + + /// Configures the size of data that's going to be uploaded as part of a + /// POST operation. + /// + /// This is called automaticsally as part of `post_fields` and should only + /// be called if data is being provided in a read callback (and even then + /// it's optional). + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_POSTFIELDSIZE_LARGE`. + pub fn post_field_size(&mut self, size: u64) -> Result<(), Error> { + // Clear anything previous to ensure we don't read past a buffer + try!(self.setopt_ptr(curl_sys::CURLOPT_POSTFIELDS, 0 as *const _)); + self.setopt_off_t(curl_sys::CURLOPT_POSTFIELDSIZE_LARGE, + size as curl_sys::curl_off_t) + } + + /// Tells libcurl you want a multipart/formdata HTTP POST to be made and you + /// instruct what data to pass on to the server in the `form` argument. + /// + /// By default this option is set to null and corresponds to + /// `CURLOPT_HTTPPOST`. + pub fn httppost(&mut self, form: Form) -> Result<(), Error> { + try!(self.setopt_ptr(curl_sys::CURLOPT_HTTPPOST, + form::raw(&form) as *const _)); + self.inner.form = Some(form); + Ok(()) + } + + /// Sets the HTTP referer header + /// + /// By default this option is not set and corresponds to `CURLOPT_REFERER`. + pub fn referer(&mut self, referer: &str) -> Result<(), Error> { + let referer = try!(CString::new(referer)); + self.setopt_str(curl_sys::CURLOPT_REFERER, &referer) + } + + /// Sets the HTTP user-agent header + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_USERAGENT`. + pub fn useragent(&mut self, useragent: &str) -> Result<(), Error> { + let useragent = try!(CString::new(useragent)); + self.setopt_str(curl_sys::CURLOPT_USERAGENT, &useragent) + } + + /// Add some headers to this HTTP request. + /// + /// If you add a header that is otherwise used internally, the value here + /// takes precedence. If a header is added with no content (like `Accept:`) + /// the internally the header will get disabled. To add a header with no + /// content, use the form `MyHeader;` (not the trailing semicolon). + /// + /// Headers must not be CRLF terminated. Many replaced headers have common + /// shortcuts which should be prefered. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_HTTPHEADER` + /// + /// # Examples + /// + /// ``` + /// use curl::easy::{Easy, List}; + /// + /// let mut list = List::new(); + /// list.append("Foo: bar").unwrap(); + /// list.append("Bar: baz").unwrap(); + /// + /// let mut handle = Easy::new(); + /// handle.url("https://www.rust-lang.org/").unwrap(); + /// handle.http_headers(list).unwrap(); + /// handle.perform().unwrap(); + /// ``` + pub fn http_headers(&mut self, list: List) -> Result<(), Error> { + let ptr = list::raw(&list); + self.inner.header_list = Some(list); + self.setopt_ptr(curl_sys::CURLOPT_HTTPHEADER, ptr as *const _) + } + + // /// Add some headers to send to the HTTP proxy. + // /// + // /// This function is essentially the same as `http_headers`. + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_PROXYHEADER` + // pub fn proxy_headers(&mut self, list: &'a List) -> Result<(), Error> { + // self.setopt_ptr(curl_sys::CURLOPT_PROXYHEADER, list.raw as *const _) + // } + + /// Set the contents of the HTTP Cookie header. + /// + /// Pass a string of the form `name=contents` for one cookie value or + /// `name1=val1; name2=val2` for multiple values. + /// + /// Using this option multiple times will only make the latest string + /// override the previous ones. This option will not enable the cookie + /// engine, use `cookie_file` or `cookie_jar` to do that. + /// + /// By default this option is not set and corresponds to `CURLOPT_COOKIE`. + pub fn cookie(&mut self, cookie: &str) -> Result<(), Error> { + let cookie = try!(CString::new(cookie)); + self.setopt_str(curl_sys::CURLOPT_COOKIE, &cookie) + } + + /// Set the file name to read cookies from. + /// + /// The cookie data can be in either the old Netscape / Mozilla cookie data + /// format or just regular HTTP headers (Set-Cookie style) dumped to a file. + /// + /// This also enables the cookie engine, making libcurl parse and send + /// cookies on subsequent requests with this handle. + /// + /// Given an empty or non-existing file or by passing the empty string ("") + /// to this option, you can enable the cookie engine without reading any + /// initial cookies. + /// + /// If you use this option multiple times, you just add more files to read. + /// Subsequent files will add more cookies. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_COOKIEFILE`. + pub fn cookie_file>(&mut self, file: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_COOKIEFILE, file.as_ref()) + } + + /// Set the file name to store cookies to. + /// + /// This will make libcurl write all internally known cookies to the file + /// when this handle is dropped. If no cookies are known, no file will be + /// created. Specify "-" as filename to instead have the cookies written to + /// stdout. Using this option also enables cookies for this session, so if + /// you for example follow a location it will make matching cookies get sent + /// accordingly. + /// + /// Note that libcurl doesn't read any cookies from the cookie jar. If you + /// want to read cookies from a file, use `cookie_file`. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_COOKIEJAR`. + pub fn cookie_jar>(&mut self, file: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_COOKIEJAR, file.as_ref()) + } + + /// Start a new cookie session + /// + /// Marks this as a new cookie "session". It will force libcurl to ignore + /// all cookies it is about to load that are "session cookies" from the + /// previous session. By default, libcurl always stores and loads all + /// cookies, independent if they are session cookies or not. Session cookies + /// are cookies without expiry date and they are meant to be alive and + /// existing for this "session" only. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_COOKIESESSION`. + pub fn cookie_session(&mut self, session: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_COOKIESESSION, session as c_long) + } + + /// Add to or manipulate cookies held in memory. + /// + /// Such a cookie can be either a single line in Netscape / Mozilla format + /// or just regular HTTP-style header (Set-Cookie: ...) format. This will + /// also enable the cookie engine. This adds that single cookie to the + /// internal cookie store. + /// + /// Exercise caution if you are using this option and multiple transfers may + /// occur. If you use the Set-Cookie format and don't specify a domain then + /// the cookie is sent for any domain (even after redirects are followed) + /// and cannot be modified by a server-set cookie. If a server sets a cookie + /// of the same name (or maybe you've imported one) then both will be sent + /// on a future transfer to that server, likely not what you intended. + /// address these issues set a domain in Set-Cookie or use the Netscape + /// format. + /// + /// Additionally, there are commands available that perform actions if you + /// pass in these exact strings: + /// + /// * "ALL" - erases all cookies held in memory + /// * "SESS" - erases all session cookies held in memory + /// * "FLUSH" - write all known cookies to the specified cookie jar + /// * "RELOAD" - reread all cookies from the cookie file + /// + /// By default this options corresponds to `CURLOPT_COOKIELIST` + pub fn cookie_list(&mut self, cookie: &str) -> Result<(), Error> { + let cookie = try!(CString::new(cookie)); + self.setopt_str(curl_sys::CURLOPT_COOKIELIST, &cookie) + } + + /// Ask for a HTTP GET request. + /// + /// By default this option is `false` and corresponds to `CURLOPT_HTTPGET`. + pub fn get(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HTTPGET, enable as c_long) + } + + // /// Ask for a HTTP GET request. + // /// + // /// By default this option is `false` and corresponds to `CURLOPT_HTTPGET`. + // pub fn http_version(&mut self, vers: &str) -> Result<(), Error> { + // self.setopt_long(curl_sys::CURLOPT_HTTPGET, enable as c_long) + // } + + /// Ignore the content-length header. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_IGNORE_CONTENT_LENGTH`. + pub fn ignore_content_length(&mut self, ignore: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_IGNORE_CONTENT_LENGTH, + ignore as c_long) + } + + /// Enable or disable HTTP content decoding. + /// + /// By default this option is `true` and corresponds to + /// `CURLOPT_HTTP_CONTENT_DECODING`. + pub fn http_content_decoding(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HTTP_CONTENT_DECODING, + enable as c_long) + } + + /// Enable or disable HTTP transfer decoding. + /// + /// By default this option is `true` and corresponds to + /// `CURLOPT_HTTP_TRANSFER_DECODING`. + pub fn http_transfer_decoding(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HTTP_TRANSFER_DECODING, + enable as c_long) + } + + // /// Timeout for the Expect: 100-continue response + // /// + // /// By default this option is 1s and corresponds to + // /// `CURLOPT_EXPECT_100_TIMEOUT_MS`. + // pub fn expect_100_timeout(&mut self, enable: bool) -> Result<(), Error> { + // self.setopt_long(curl_sys::CURLOPT_HTTP_TRANSFER_DECODING, + // enable as c_long) + // } + + // /// Wait for pipelining/multiplexing. + // /// + // /// Tells libcurl to prefer to wait for a connection to confirm or deny that + // /// it can do pipelining or multiplexing before continuing. + // /// + // /// When about to perform a new transfer that allows pipelining or + // /// multiplexing, libcurl will check for existing connections to re-use and + // /// pipeline on. If no such connection exists it will immediately continue + // /// and create a fresh new connection to use. + // /// + // /// By setting this option to `true` - having `pipeline` enabled for the + // /// multi handle this transfer is associated with - libcurl will instead + // /// wait for the connection to reveal if it is possible to + // /// pipeline/multiplex on before it continues. This enables libcurl to much + // /// better keep the number of connections to a minimum when using pipelining + // /// or multiplexing protocols. + // /// + // /// The effect thus becomes that with this option set, libcurl prefers to + // /// wait and re-use an existing connection for pipelining rather than the + // /// opposite: prefer to open a new connection rather than waiting. + // /// + // /// The waiting time is as long as it takes for the connection to get up and + // /// for libcurl to get the necessary response back that informs it about its + // /// protocol and support level. + // pub fn http_pipewait(&mut self, enable: bool) -> Result<(), Error> { + // } + + + // ========================================================================= + // Protocol Options + + /// Indicates the range that this request should retrieve. + /// + /// The string provided should be of the form `N-M` where either `N` or `M` + /// can be left out. For HTTP transfers multiple ranges separated by commas + /// are also accepted. + /// + /// By default this option is not set and corresponds to `CURLOPT_RANGE`. + pub fn range(&mut self, range: &str) -> Result<(), Error> { + let range = try!(CString::new(range)); + self.setopt_str(curl_sys::CURLOPT_RANGE, &range) + } + + /// Set a point to resume transfer from + /// + /// Specify the offset in bytes you want the transfer to start from. + /// + /// By default this option is 0 and corresponds to + /// `CURLOPT_RESUME_FROM_LARGE`. + pub fn resume_from(&mut self, from: u64) -> Result<(), Error> { + self.setopt_off_t(curl_sys::CURLOPT_RESUME_FROM_LARGE, + from as curl_sys::curl_off_t) + } + + /// Set a custom request string + /// + /// Specifies that a custom request will be made (e.g. a custom HTTP + /// method). This does not change how libcurl performs internally, just + /// changes the string sent to the server. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_CUSTOMREQUEST`. + pub fn custom_request(&mut self, request: &str) -> Result<(), Error> { + let request = try!(CString::new(request)); + self.setopt_str(curl_sys::CURLOPT_CUSTOMREQUEST, &request) + } + + /// Get the modification time of the remote resource + /// + /// If true, libcurl will attempt to get the modification time of the + /// remote document in this operation. This requires that the remote server + /// sends the time or replies to a time querying command. The `filetime` + /// function can be used after a transfer to extract the received time (if + /// any). + /// + /// By default this option is `false` and corresponds to `CURLOPT_FILETIME` + pub fn fetch_filetime(&mut self, fetch: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_FILETIME, fetch as c_long) + } + + /// Indicate whether to download the request without getting the body + /// + /// This is useful, for example, for doing a HEAD request. + /// + /// By default this option is `false` and corresponds to `CURLOPT_NOBODY`. + pub fn nobody(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_NOBODY, enable as c_long) + } + + /// Set the size of the input file to send off. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_INFILESIZE_LARGE`. + pub fn in_filesize(&mut self, size: u64) -> Result<(), Error> { + self.setopt_off_t(curl_sys::CURLOPT_INFILESIZE_LARGE, + size as curl_sys::curl_off_t) + } + + /// Enable or disable data upload. + /// + /// This means that a PUT request will be made for HTTP and probably wants + /// to be combined with the read callback as well as the `in_filesize` + /// method. + /// + /// By default this option is `false` and corresponds to `CURLOPT_UPLOAD`. + pub fn upload(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_UPLOAD, enable as c_long) + } + + /// Configure the maximum file size to download. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_MAXFILESIZE_LARGE`. + pub fn max_filesize(&mut self, size: u64) -> Result<(), Error> { + self.setopt_off_t(curl_sys::CURLOPT_MAXFILESIZE_LARGE, + size as curl_sys::curl_off_t) + } + + /// Selects a condition for a time request. + /// + /// This value indicates how the `time_value` option is interpreted. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_TIMECONDITION`. + pub fn time_condition(&mut self, cond: TimeCondition) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TIMECONDITION, cond as c_long) + } + + /// Sets the time value for a conditional request. + /// + /// The value here should be the number of seconds elapsed since January 1, + /// 1970. To pass how to interpret this value, use `time_condition`. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_TIMEVALUE`. + pub fn time_value(&mut self, val: i64) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_TIMEVALUE, val as c_long) + } + + // ========================================================================= + // Connection Options + + /// Set maximum time the request is allowed to take. + /// + /// Normally, name lookups can take a considerable time and limiting + /// operations to less than a few minutes risk aborting perfectly normal + /// operations. + /// + /// If libcurl is built to use the standard system name resolver, that + /// portion of the transfer will still use full-second resolution for + /// timeouts with a minimum timeout allowed of one second. + /// + /// In unix-like systems, this might cause signals to be used unless + /// `nosignal` is set. + /// + /// Since this puts a hard limit for how long a request is allowed to + /// take, it has limited use in dynamic use cases with varying transfer + /// times. You are then advised to explore `low_speed_limit`, + /// `low_speed_time` or using `progress_function` to implement your own + /// timeout logic. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_TIMEOUT_MS`. + pub fn timeout(&mut self, timeout: Duration) -> Result<(), Error> { + // TODO: checked arithmetic and casts + // TODO: use CURLOPT_TIMEOUT if the timeout is too great + let ms = timeout.as_secs() * 1000 + + (timeout.subsec_nanos() / 1_000_000) as u64; + self.setopt_long(curl_sys::CURLOPT_TIMEOUT_MS, ms as c_long) + + } + + /// Set the low speed limit in bytes per second. + /// + /// This specifies the average transfer speed in bytes per second that the + /// transfer should be below during `low_speed_time` for libcurl to consider + /// it to be too slow and abort. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_LOW_SPEED_LIMIT`. + pub fn low_speed_limit(&mut self, limit: u32) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_LOW_SPEED_LIMIT, limit as c_long) + } + + /// Set the low speed time period. + /// + /// Specifies the window of time for which if the transfer rate is below + /// `low_speed_limit` the request will be aborted. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_LOW_SPEED_TIME`. + pub fn low_speed_time(&mut self, dur: Duration) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_LOW_SPEED_TIME, + dur.as_secs() as c_long) + } + + /// Rate limit data upload speed + /// + /// If an upload exceeds this speed (counted in bytes per second) on + /// cumulative average during the transfer, the transfer will pause to keep + /// the average rate less than or equal to the parameter value. + /// + /// By default this option is not set (unlimited speed) and corresponds to + /// `CURLOPT_MAX_SEND_SPEED_LARGE`. + pub fn max_send_speed(&mut self, speed: u64) -> Result<(), Error> { + self.setopt_off_t(curl_sys::CURLOPT_MAX_SEND_SPEED_LARGE, + speed as curl_sys::curl_off_t) + } + + /// Rate limit data download speed + /// + /// If a download exceeds this speed (counted in bytes per second) on + /// cumulative average during the transfer, the transfer will pause to keep + /// the average rate less than or equal to the parameter value. + /// + /// By default this option is not set (unlimited speed) and corresponds to + /// `CURLOPT_MAX_RECV_SPEED_LARGE`. + pub fn max_recv_speed(&mut self, speed: u64) -> Result<(), Error> { + self.setopt_off_t(curl_sys::CURLOPT_MAX_RECV_SPEED_LARGE, + speed as curl_sys::curl_off_t) + } + + /// Set the maximum connection cache size. + /// + /// The set amount will be the maximum number of simultaneously open + /// persistent connections that libcurl may cache in the pool associated + /// with this handle. The default is 5, and there isn't much point in + /// changing this value unless you are perfectly aware of how this works and + /// changes libcurl's behaviour. This concerns connections using any of the + /// protocols that support persistent connections. + /// + /// When reaching the maximum limit, curl closes the oldest one in the cache + /// to prevent increasing the number of open connections. + /// + /// By default this option is set to 5 and corresponds to + /// `CURLOPT_MAXCONNECTS` + pub fn max_connects(&mut self, max: u32) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_MAXCONNECTS, max as c_long) + } + + /// Force a new connection to be used. + /// + /// Makes the next transfer use a new (fresh) connection by force instead of + /// trying to re-use an existing one. This option should be used with + /// caution and only if you understand what it does as it may seriously + /// impact performance. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_FRESH_CONNECT`. + pub fn fresh_connect(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_FRESH_CONNECT, enable as c_long) + } + + /// Make connection get closed at once after use. + /// + /// Makes libcurl explicitly close the connection when done with the + /// transfer. Normally, libcurl keeps all connections alive when done with + /// one transfer in case a succeeding one follows that can re-use them. + /// This option should be used with caution and only if you understand what + /// it does as it can seriously impact performance. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_FORBID_REUSE`. + pub fn forbid_reuse(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_FORBID_REUSE, enable as c_long) + } + + /// Timeout for the connect phase + /// + /// This is the maximum time that you allow the connection phase to the + /// server to take. This only limits the connection phase, it has no impact + /// once it has connected. + /// + /// By default this value is 300 seconds and corresponds to + /// `CURLOPT_CONNECTTIMEOUT_MS`. + pub fn connect_timeout(&mut self, timeout: Duration) -> Result<(), Error> { + let ms = timeout.as_secs() * 1000 + + (timeout.subsec_nanos() / 1_000_000) as u64; + self.setopt_long(curl_sys::CURLOPT_CONNECTTIMEOUT_MS, ms as c_long) + } + + /// Specify which IP protocol version to use + /// + /// Allows an application to select what kind of IP addresses to use when + /// resolving host names. This is only interesting when using host names + /// that resolve addresses using more than one version of IP. + /// + /// By default this value is "any" and corresponds to `CURLOPT_IPRESOLVE`. + pub fn ip_resolve(&mut self, resolve: IpResolve) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_IPRESOLVE, resolve as c_long) + } + + /// Specify custom host name to IP address resolves. + /// + /// Allows specifying hostname to IP mappins to use before trying the + /// system resolver. + /// + /// # Examples + /// ``` + /// use curl::easy::{Easy, List}; + /// + /// let mut list = List::new(); + /// list.append("www.rust-lang.org:443:13.32.234.49").unwrap(); + /// + /// let mut handle = Easy::new(); + /// handle.url("https://www.rust-lang.org/").unwrap(); + /// handle.resolve(list).unwrap(); + /// handle.perform().unwrap(); + /// ``` + pub fn resolve(&mut self, list: List) -> Result<(), Error> { + let ptr = list::raw(&list); + self.inner.resolve_list = Some(list); + self.setopt_ptr(curl_sys::CURLOPT_RESOLVE, ptr as *const _) + } + + + /// Configure whether to stop when connected to target server + /// + /// When enabled it tells the library to perform all the required proxy + /// authentication and connection setup, but no data transfer, and then + /// return. + /// + /// The option can be used to simply test a connection to a server. + /// + /// By default this value is `false` and corresponds to + /// `CURLOPT_CONNECT_ONLY`. + pub fn connect_only(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_CONNECT_ONLY, enable as c_long) + } + + // /// Set interface to speak DNS over. + // /// + // /// Set the name of the network interface that the DNS resolver should bind + // /// to. This must be an interface name (not an address). + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_DNS_INTERFACE`. + // pub fn dns_interface(&mut self, interface: &str) -> Result<(), Error> { + // let interface = try!(CString::new(interface)); + // self.setopt_str(curl_sys::CURLOPT_DNS_INTERFACE, &interface) + // } + // + // /// IPv4 address to bind DNS resolves to + // /// + // /// Set the local IPv4 address that the resolver should bind to. The + // /// argument should be of type char * and contain a single numerical IPv4 + // /// address as a string. + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_DNS_LOCAL_IP4`. + // pub fn dns_local_ip4(&mut self, ip: &str) -> Result<(), Error> { + // let ip = try!(CString::new(ip)); + // self.setopt_str(curl_sys::CURLOPT_DNS_LOCAL_IP4, &ip) + // } + // + // /// IPv6 address to bind DNS resolves to + // /// + // /// Set the local IPv6 address that the resolver should bind to. The + // /// argument should be of type char * and contain a single numerical IPv6 + // /// address as a string. + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_DNS_LOCAL_IP6`. + // pub fn dns_local_ip6(&mut self, ip: &str) -> Result<(), Error> { + // let ip = try!(CString::new(ip)); + // self.setopt_str(curl_sys::CURLOPT_DNS_LOCAL_IP6, &ip) + // } + // + // /// Set preferred DNS servers. + // /// + // /// Provides a list of DNS servers to be used instead of the system default. + // /// The format of the dns servers option is: + // /// + // /// ```text + // /// host[:port],[host[:port]]... + // /// ``` + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_DNS_SERVERS`. + // pub fn dns_servers(&mut self, servers: &str) -> Result<(), Error> { + // let servers = try!(CString::new(servers)); + // self.setopt_str(curl_sys::CURLOPT_DNS_SERVERS, &servers) + // } + + // ========================================================================= + // SSL/Security Options + + /// Sets the SSL client certificate. + /// + /// The string should be the file name of your client certificate. The + /// default format is "P12" on Secure Transport and "PEM" on other engines, + /// and can be changed with `ssl_cert_type`. + /// + /// With NSS or Secure Transport, this can also be the nickname of the + /// certificate you wish to authenticate with as it is named in the security + /// database. If you want to use a file from the current directory, please + /// precede it with "./" prefix, in order to avoid confusion with a + /// nickname. + /// + /// When using a client certificate, you most likely also need to provide a + /// private key with `ssl_key`. + /// + /// By default this option is not set and corresponds to `CURLOPT_SSLCERT`. + pub fn ssl_cert>(&mut self, cert: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_SSLCERT, cert.as_ref()) + } + + /// Specify type of the client SSL certificate. + /// + /// The string should be the format of your certificate. Supported formats + /// are "PEM" and "DER", except with Secure Transport. OpenSSL (versions + /// 0.9.3 and later) and Secure Transport (on iOS 5 or later, or OS X 10.7 + /// or later) also support "P12" for PKCS#12-encoded files. + /// + /// By default this option is "PEM" and corresponds to + /// `CURLOPT_SSLCERTTYPE`. + pub fn ssl_cert_type(&mut self, kind: &str) -> Result<(), Error> { + let kind = try!(CString::new(kind)); + self.setopt_str(curl_sys::CURLOPT_SSLCERTTYPE, &kind) + } + + /// Specify private keyfile for TLS and SSL client cert. + /// + /// The string should be the file name of your private key. The default + /// format is "PEM" and can be changed with `ssl_key_type`. + /// + /// (iOS and Mac OS X only) This option is ignored if curl was built against + /// Secure Transport. Secure Transport expects the private key to be already + /// present in the keychain or PKCS#12 file containing the certificate. + /// + /// By default this option is not set and corresponds to `CURLOPT_SSLKEY`. + pub fn ssl_key>(&mut self, key: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_SSLKEY, key.as_ref()) + } + + /// Set type of the private key file. + /// + /// The string should be the format of your private key. Supported formats + /// are "PEM", "DER" and "ENG". + /// + /// The format "ENG" enables you to load the private key from a crypto + /// engine. In this case `ssl_key` is used as an identifier passed to + /// the engine. You have to set the crypto engine with `ssl_engine`. + /// "DER" format key file currently does not work because of a bug in + /// OpenSSL. + /// + /// By default this option is "PEM" and corresponds to + /// `CURLOPT_SSLKEYTYPE`. + pub fn ssl_key_type(&mut self, kind: &str) -> Result<(), Error> { + let kind = try!(CString::new(kind)); + self.setopt_str(curl_sys::CURLOPT_SSLKEYTYPE, &kind) + } + + /// Set passphrase to private key. + /// + /// This will be used as the password required to use the `ssl_key`. + /// You never needed a pass phrase to load a certificate but you need one to + /// load your private key. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_KEYPASSWD`. + pub fn key_password(&mut self, password: &str) -> Result<(), Error> { + let password = try!(CString::new(password)); + self.setopt_str(curl_sys::CURLOPT_KEYPASSWD, &password) + } + + /// Set the SSL engine identifier. + /// + /// This will be used as the identifier for the crypto engine you want to + /// use for your private key. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_SSLENGINE`. + pub fn ssl_engine(&mut self, engine: &str) -> Result<(), Error> { + let engine = try!(CString::new(engine)); + self.setopt_str(curl_sys::CURLOPT_SSLENGINE, &engine) + } + + /// Make this handle's SSL engine the default. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_SSLENGINE_DEFAULT`. + pub fn ssl_engine_default(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_SSLENGINE_DEFAULT, enable as c_long) + } + + // /// Enable TLS false start. + // /// + // /// This option determines whether libcurl should use false start during the + // /// TLS handshake. False start is a mode where a TLS client will start + // /// sending application data before verifying the server's Finished message, + // /// thus saving a round trip when performing a full handshake. + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_SSL_FALSESTARTE`. + // pub fn ssl_false_start(&mut self, enable: bool) -> Result<(), Error> { + // self.setopt_long(curl_sys::CURLOPT_SSLENGINE_DEFAULT, enable as c_long) + // } + + /// Set preferred HTTP version. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_HTTP_VERSION`. + pub fn http_version(&mut self, version: HttpVersion) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_HTTP_VERSION, version as c_long) + } + + /// Set preferred TLS/SSL version. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_SSLVERSION`. + pub fn ssl_version(&mut self, version: SslVersion) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_SSLVERSION, version as c_long) + } + + /// Verify the certificate's name against host. + /// + /// This should be disabled with great caution! It basically disables the + /// security features of SSL if it is disabled. + /// + /// By default this option is set to `true` and corresponds to + /// `CURLOPT_SSL_VERIFYHOST`. + pub fn ssl_verify_host(&mut self, verify: bool) -> Result<(), Error> { + let val = if verify {2} else {0}; + self.setopt_long(curl_sys::CURLOPT_SSL_VERIFYHOST, val) + } + + /// Verify the peer's SSL certificate. + /// + /// This should be disabled with great caution! It basically disables the + /// security features of SSL if it is disabled. + /// + /// By default this option is set to `true` and corresponds to + /// `CURLOPT_SSL_VERIFYPEER`. + pub fn ssl_verify_peer(&mut self, verify: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_SSL_VERIFYPEER, verify as c_long) + } + + // /// Verify the certificate's status. + // /// + // /// This option determines whether libcurl verifies the status of the server + // /// cert using the "Certificate Status Request" TLS extension (aka. OCSP + // /// stapling). + // /// + // /// By default this option is set to `false` and corresponds to + // /// `CURLOPT_SSL_VERIFYSTATUS`. + // pub fn ssl_verify_status(&mut self, verify: bool) -> Result<(), Error> { + // self.setopt_long(curl_sys::CURLOPT_SSL_VERIFYSTATUS, verify as c_long) + // } + + /// Specify the path to Certificate Authority (CA) bundle + /// + /// The file referenced should hold one or more certificates to verify the + /// peer with. + /// + /// This option is by default set to the system path where libcurl's cacert + /// bundle is assumed to be stored, as established at build time. + /// + /// If curl is built against the NSS SSL library, the NSS PEM PKCS#11 module + /// (libnsspem.so) needs to be available for this option to work properly. + /// + /// By default this option is the system defaults, and corresponds to + /// `CURLOPT_CAINFO`. + pub fn cainfo>(&mut self, path: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_CAINFO, path.as_ref()) + } + + /// Set the issuer SSL certificate filename + /// + /// Specifies a file holding a CA certificate in PEM format. If the option + /// is set, an additional check against the peer certificate is performed to + /// verify the issuer is indeed the one associated with the certificate + /// provided by the option. This additional check is useful in multi-level + /// PKI where one needs to enforce that the peer certificate is from a + /// specific branch of the tree. + /// + /// This option makes sense only when used in combination with the + /// `ssl_verify_peer` option. Otherwise, the result of the check is not + /// considered as failure. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_ISSUERCERT`. + pub fn issuer_cert>(&mut self, path: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_ISSUERCERT, path.as_ref()) + } + + /// Specify directory holding CA certificates + /// + /// Names a directory holding multiple CA certificates to verify the peer + /// with. If libcurl is built against OpenSSL, the certificate directory + /// must be prepared using the openssl c_rehash utility. This makes sense + /// only when used in combination with the `ssl_verify_peer` option. + /// + /// By default this option is not set and corresponds to `CURLOPT_CAPATH`. + pub fn capath>(&mut self, path: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_CAPATH, path.as_ref()) + } + + /// Specify a Certificate Revocation List file + /// + /// Names a file with the concatenation of CRL (in PEM format) to use in the + /// certificate validation that occurs during the SSL exchange. + /// + /// When curl is built to use NSS or GnuTLS, there is no way to influence + /// the use of CRL passed to help in the verification process. When libcurl + /// is built with OpenSSL support, X509_V_FLAG_CRL_CHECK and + /// X509_V_FLAG_CRL_CHECK_ALL are both set, requiring CRL check against all + /// the elements of the certificate chain if a CRL file is passed. + /// + /// This option makes sense only when used in combination with the + /// `ssl_verify_peer` option. + /// + /// A specific error code (`is_ssl_crl_badfile`) is defined with the + /// option. It is returned when the SSL exchange fails because the CRL file + /// cannot be loaded. A failure in certificate verification due to a + /// revocation information found in the CRL does not trigger this specific + /// error. + /// + /// By default this option is not set and corresponds to `CURLOPT_CRLFILE`. + pub fn crlfile>(&mut self, path: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_CRLFILE, path.as_ref()) + } + + /// Request SSL certificate information + /// + /// Enable libcurl's certificate chain info gatherer. With this enabled, + /// libcurl will extract lots of information and data about the certificates + /// in the certificate chain used in the SSL connection. + /// + /// By default this option is `false` and corresponds to + /// `CURLOPT_CERTINFO`. + pub fn certinfo(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_CERTINFO, enable as c_long) + } + + // /// Set pinned public key. + // /// + // /// Pass a pointer to a zero terminated string as parameter. The string can + // /// be the file name of your pinned public key. The file format expected is + // /// "PEM" or "DER". The string can also be any number of base64 encoded + // /// sha256 hashes preceded by "sha256//" and separated by ";" + // /// + // /// When negotiating a TLS or SSL connection, the server sends a certificate + // /// indicating its identity. A public key is extracted from this certificate + // /// and if it does not exactly match the public key provided to this option, + // /// curl will abort the connection before sending or receiving any data. + // /// + // /// By default this option is not set and corresponds to + // /// `CURLOPT_PINNEDPUBLICKEY`. + // pub fn pinned_public_key(&mut self, enable: bool) -> Result<(), Error> { + // self.setopt_long(curl_sys::CURLOPT_CERTINFO, enable as c_long) + // } + + /// Specify a source for random data + /// + /// The file will be used to read from to seed the random engine for SSL and + /// more. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_RANDOM_FILE`. + pub fn random_file>(&mut self, p: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_RANDOM_FILE, p.as_ref()) + } + + /// Specify EGD socket path. + /// + /// Indicates the path name to the Entropy Gathering Daemon socket. It will + /// be used to seed the random engine for SSL. + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_EGDSOCKET`. + pub fn egd_socket>(&mut self, p: P) -> Result<(), Error> { + self.setopt_path(curl_sys::CURLOPT_EGDSOCKET, p.as_ref()) + } + + /// Specify ciphers to use for TLS. + /// + /// Holds the list of ciphers to use for the SSL connection. The list must + /// be syntactically correct, it consists of one or more cipher strings + /// separated by colons. Commas or spaces are also acceptable separators + /// but colons are normally used, !, - and + can be used as operators. + /// + /// For OpenSSL and GnuTLS valid examples of cipher lists include 'RC4-SHA', + /// ´SHA1+DES´, 'TLSv1' and 'DEFAULT'. The default list is normally set when + /// you compile OpenSSL. + /// + /// You'll find more details about cipher lists on this URL: + /// + /// https://www.openssl.org/docs/apps/ciphers.html + /// + /// For NSS, valid examples of cipher lists include 'rsa_rc4_128_md5', + /// ´rsa_aes_128_sha´, etc. With NSS you don't add/remove ciphers. If one + /// uses this option then all known ciphers are disabled and only those + /// passed in are enabled. + /// + /// You'll find more details about the NSS cipher lists on this URL: + /// + /// http://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html#Directives + /// + /// By default this option is not set and corresponds to + /// `CURLOPT_SSL_CIPHER_LIST`. + pub fn ssl_cipher_list(&mut self, ciphers: &str) -> Result<(), Error> { + let ciphers = try!(CString::new(ciphers)); + self.setopt_str(curl_sys::CURLOPT_SSL_CIPHER_LIST, &ciphers) + } + + /// Enable or disable use of the SSL session-ID cache + /// + /// By default all transfers are done using the cache enabled. While nothing + /// ever should get hurt by attempting to reuse SSL session-IDs, there seem + /// to be or have been broken SSL implementations in the wild that may + /// require you to disable this in order for you to succeed. + /// + /// This corresponds to the `CURLOPT_SSL_SESSIONID_CACHE` option. + pub fn ssl_sessionid_cache(&mut self, enable: bool) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_SSL_SESSIONID_CACHE, + enable as c_long) + } + + /// Set SSL behavior options + /// + /// Inform libcurl about SSL specific behaviors. + /// + /// This corresponds to the `CURLOPT_SSL_OPTIONS` option. + pub fn ssl_options(&mut self, bits: &SslOpt) -> Result<(), Error> { + self.setopt_long(curl_sys::CURLOPT_SSL_OPTIONS, bits.bits) + } + + // /// Set SSL behavior options for proxies + // /// + // /// Inform libcurl about SSL specific behaviors. + // /// + // /// This corresponds to the `CURLOPT_PROXY_SSL_OPTIONS` option. + // pub fn proxy_ssl_options(&mut self, bits: &SslOpt) -> Result<(), Error> { + // self.setopt_long(curl_sys::CURLOPT_PROXY_SSL_OPTIONS, bits.bits) + // } + + // /// Stores a private pointer-sized piece of data. + // /// + // /// This can be retrieved through the `private` function and otherwise + // /// libcurl does not tamper with this value. This corresponds to + // /// `CURLOPT_PRIVATE` and defaults to 0. + // pub fn set_private(&mut self, private: usize) -> Result<(), Error> { + // self.setopt_ptr(curl_sys::CURLOPT_PRIVATE, private as *const _) + // } + // + // /// Fetches this handle's private pointer-sized piece of data. + // /// + // /// This corresponds to `CURLINFO_PRIVATE` and defaults to 0. + // pub fn private(&mut self) -> Result { + // self.getopt_ptr(curl_sys::CURLINFO_PRIVATE).map(|p| p as usize) + // } + + // ========================================================================= + // getters + + /// Get the last used URL + /// + /// In cases when you've asked libcurl to follow redirects, it may + /// not be the same value you set with `url`. + /// + /// This methods corresponds to the `CURLINFO_EFFECTIVE_URL` option. + /// + /// Returns `Ok(None)` if no effective url is listed or `Err` if an error + /// happens or the underlying bytes aren't valid utf-8. + pub fn effective_url(&mut self) -> Result, Error> { + self.getopt_str(curl_sys::CURLINFO_EFFECTIVE_URL) + } + + /// Get the last used URL, in bytes + /// + /// In cases when you've asked libcurl to follow redirects, it may + /// not be the same value you set with `url`. + /// + /// This methods corresponds to the `CURLINFO_EFFECTIVE_URL` option. + /// + /// Returns `Ok(None)` if no effective url is listed or `Err` if an error + /// happens or the underlying bytes aren't valid utf-8. + pub fn effective_url_bytes(&mut self) -> Result, Error> { + self.getopt_bytes(curl_sys::CURLINFO_EFFECTIVE_URL) + } + + /// Get the last response code + /// + /// The stored value will be zero if no server response code has been + /// received. Note that a proxy's CONNECT response should be read with + /// `http_connectcode` and not this. + /// + /// Corresponds to `CURLINFO_RESPONSE_CODE` and returns an error if this + /// option is not supported. + pub fn response_code(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_RESPONSE_CODE).map(|c| c as u32) + } + + /// Get the CONNECT response code + /// + /// Returns the last received HTTP proxy response code to a CONNECT request. + /// The returned value will be zero if no such response code was available. + /// + /// Corresponds to `CURLINFO_HTTP_CONNECTCODE` and returns an error if this + /// option is not supported. + pub fn http_connectcode(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_HTTP_CONNECTCODE).map(|c| c as u32) + } + + /// Get the remote time of the retrieved document + /// + /// Returns the remote time of the retrieved document (in number of seconds + /// since 1 Jan 1970 in the GMT/UTC time zone). If you get `None`, it can be + /// because of many reasons (it might be unknown, the server might hide it + /// or the server doesn't support the command that tells document time etc) + /// and the time of the document is unknown. + /// + /// Note that you must tell the server to collect this information before + /// the transfer is made, by using the `filetime` method to + /// or you will unconditionally get a `None` back. + /// + /// This corresponds to `CURLINFO_FILETIME` and may return an error if the + /// option is not supported + pub fn filetime(&mut self) -> Result, Error> { + self.getopt_long(curl_sys::CURLINFO_FILETIME).map(|r| { + if r == -1 { + None + } else { + Some(r as i64) + } + }) + } + + /// Get total time of previous transfer + /// + /// Returns the total time for the previous transfer, + /// including name resolving, TCP connect etc. + /// + /// Corresponds to `CURLINFO_TOTAL_TIME` and may return an error if the + /// option isn't supported. + pub fn total_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_TOTAL_TIME) + .map(double_seconds_to_duration) + } + + /// Get the name lookup time + /// + /// Returns the total time from the start + /// until the name resolving was completed. + /// + /// Corresponds to `CURLINFO_NAMELOOKUP_TIME` and may return an error if the + /// option isn't supported. + pub fn namelookup_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_NAMELOOKUP_TIME) + .map(double_seconds_to_duration) + } + + /// Get the time until connect + /// + /// Returns the total time from the start + /// until the connection to the remote host (or proxy) was completed. + /// + /// Corresponds to `CURLINFO_CONNECT_TIME` and may return an error if the + /// option isn't supported. + pub fn connect_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_CONNECT_TIME) + .map(double_seconds_to_duration) + } + + /// Get the time until the SSL/SSH handshake is completed + /// + /// Returns the total time it took from the start until the SSL/SSH + /// connect/handshake to the remote host was completed. This time is most often + /// very near to the `pretransfer_time` time, except for cases such as + /// HTTP pipelining where the pretransfer time can be delayed due to waits in + /// line for the pipeline and more. + /// + /// Corresponds to `CURLINFO_APPCONNECT_TIME` and may return an error if the + /// option isn't supported. + pub fn appconnect_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_APPCONNECT_TIME) + .map(double_seconds_to_duration) + } + + /// Get the time until the file transfer start + /// + /// Returns the total time it took from the start until the file + /// transfer is just about to begin. This includes all pre-transfer commands + /// and negotiations that are specific to the particular protocol(s) involved. + /// It does not involve the sending of the protocol- specific request that + /// triggers a transfer. + /// + /// Corresponds to `CURLINFO_PRETRANSFER_TIME` and may return an error if the + /// option isn't supported. + pub fn pretransfer_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_PRETRANSFER_TIME) + .map(double_seconds_to_duration) + } + + /// Get the time until the first byte is received + /// + /// Returns the total time it took from the start until the first + /// byte is received by libcurl. This includes `pretransfer_time` and + /// also the time the server needs to calculate the result. + /// + /// Corresponds to `CURLINFO_STARTTRANSFER_TIME` and may return an error if the + /// option isn't supported. + pub fn starttransfer_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_STARTTRANSFER_TIME) + .map(double_seconds_to_duration) + } + + /// Get the time for all redirection steps + /// + /// Returns the total time it took for all redirection steps + /// include name lookup, connect, pretransfer and transfer before final + /// transaction was started. `redirect_time` contains the complete + /// execution time for multiple redirections. + /// + /// Corresponds to `CURLINFO_REDIRECT_TIME` and may return an error if the + /// option isn't supported. + pub fn redirect_time(&mut self) -> Result { + self.getopt_double(curl_sys::CURLINFO_REDIRECT_TIME) + .map(double_seconds_to_duration) + } + + /// Get the number of redirects + /// + /// Corresponds to `CURLINFO_REDIRECT_COUNT` and may return an error if the + /// option isn't supported. + pub fn redirect_count(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_REDIRECT_COUNT).map(|c| c as u32) + } + + /// Get the URL a redirect would go to + /// + /// Returns the URL a redirect would take you to if you would enable + /// `follow_location`. This can come very handy if you think using the + /// built-in libcurl redirect logic isn't good enough for you but you would + /// still prefer to avoid implementing all the magic of figuring out the new + /// URL. + /// + /// Corresponds to `CURLINFO_REDIRECT_URL` and may return an error if the + /// url isn't valid utf-8 or an error happens. + pub fn redirect_url(&mut self) -> Result, Error> { + self.getopt_str(curl_sys::CURLINFO_REDIRECT_URL) + } + + /// Get the URL a redirect would go to, in bytes + /// + /// Returns the URL a redirect would take you to if you would enable + /// `follow_location`. This can come very handy if you think using the + /// built-in libcurl redirect logic isn't good enough for you but you would + /// still prefer to avoid implementing all the magic of figuring out the new + /// URL. + /// + /// Corresponds to `CURLINFO_REDIRECT_URL` and may return an error. + pub fn redirect_url_bytes(&mut self) -> Result, Error> { + self.getopt_bytes(curl_sys::CURLINFO_REDIRECT_URL) + } + + /// Get size of retrieved headers + /// + /// Corresponds to `CURLINFO_HEADER_SIZE` and may return an error if the + /// option isn't supported. + pub fn header_size(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_HEADER_SIZE).map(|c| c as u64) + } + + /// Get size of sent request. + /// + /// Corresponds to `CURLINFO_REQUEST_SIZE` and may return an error if the + /// option isn't supported. + pub fn request_size(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_REQUEST_SIZE).map(|c| c as u64) + } + + /// Get Content-Type + /// + /// Returns the content-type of the downloaded object. This is the value + /// read from the Content-Type: field. If you get `None`, it means that the + /// server didn't send a valid Content-Type header or that the protocol + /// used doesn't support this. + /// + /// Corresponds to `CURLINFO_CONTENT_TYPE` and may return an error if the + /// option isn't supported. + pub fn content_type(&mut self) -> Result, Error> { + self.getopt_str(curl_sys::CURLINFO_CONTENT_TYPE) + } + + /// Get Content-Type, in bytes + /// + /// Returns the content-type of the downloaded object. This is the value + /// read from the Content-Type: field. If you get `None`, it means that the + /// server didn't send a valid Content-Type header or that the protocol + /// used doesn't support this. + /// + /// Corresponds to `CURLINFO_CONTENT_TYPE` and may return an error if the + /// option isn't supported. + pub fn content_type_bytes(&mut self) -> Result, Error> { + self.getopt_bytes(curl_sys::CURLINFO_CONTENT_TYPE) + } + + /// Get errno number from last connect failure. + /// + /// Note that the value is only set on failure, it is not reset upon a + /// successful operation. The number is OS and system specific. + /// + /// Corresponds to `CURLINFO_OS_ERRNO` and may return an error if the + /// option isn't supported. + pub fn os_errno(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_OS_ERRNO).map(|c| c as i32) + } + + /// Get IP address of last connection. + /// + /// Returns a string holding the IP address of the most recent connection + /// done with this curl handle. This string may be IPv6 when that is + /// enabled. + /// + /// Corresponds to `CURLINFO_PRIMARY_IP` and may return an error if the + /// option isn't supported. + pub fn primary_ip(&mut self) -> Result, Error> { + self.getopt_str(curl_sys::CURLINFO_PRIMARY_IP) + } + + /// Get the latest destination port number + /// + /// Corresponds to `CURLINFO_PRIMARY_PORT` and may return an error if the + /// option isn't supported. + pub fn primary_port(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_PRIMARY_PORT).map(|c| c as u16) + } + + /// Get local IP address of last connection + /// + /// Returns a string holding the IP address of the local end of most recent + /// connection done with this curl handle. This string may be IPv6 when that + /// is enabled. + /// + /// Corresponds to `CURLINFO_LOCAL_IP` and may return an error if the + /// option isn't supported. + pub fn local_ip(&mut self) -> Result, Error> { + self.getopt_str(curl_sys::CURLINFO_LOCAL_IP) + } + + /// Get the latest local port number + /// + /// Corresponds to `CURLINFO_LOCAL_PORT` and may return an error if the + /// option isn't supported. + pub fn local_port(&mut self) -> Result { + self.getopt_long(curl_sys::CURLINFO_LOCAL_PORT).map(|c| c as u16) + } + + /// Get all known cookies + /// + /// Returns a linked-list of all cookies cURL knows (expired ones, too). + /// + /// Corresponds to the `CURLINFO_COOKIELIST` option and may return an error + /// if the option isn't supported. + pub fn cookies(&mut self) -> Result { + unsafe { + let mut list = 0 as *mut _; + let rc = curl_sys::curl_easy_getinfo(self.inner.handle, + curl_sys::CURLINFO_COOKIELIST, + &mut list); + try!(self.cvt(rc)); + Ok(list::from_raw(list)) + } + } + + // ========================================================================= + // Other methods + + /// After options have been set, this will perform the transfer described by + /// the options. + /// + /// This performs the request in a synchronous fashion. This can be used + /// multiple times for one easy handle and libcurl will attempt to re-use + /// the same connection for all transfers. + /// + /// This method will preserve all options configured in this handle for the + /// next request, and if that is not desired then the options can be + /// manually reset or the `reset` method can be called. + /// + /// Note that this method takes `&self`, which is quite important! This + /// allows applications to close over the handle in various callbacks to + /// call methods like `unpause_write` and `unpause_read` while a transfer is + /// in progress. + pub fn perform(&self) -> Result<(), Error> { + let ret = unsafe { + self.cvt(curl_sys::curl_easy_perform(self.inner.handle)) + }; + panic::propagate(); + return ret + } + + /// Unpause reading on a connection. + /// + /// Using this function, you can explicitly unpause a connection that was + /// previously paused. + /// + /// A connection can be paused by letting the read or the write callbacks + /// return `ReadError::Pause` or `WriteError::Pause`. + /// + /// To unpause, you may for example call this from the progress callback + /// which gets called at least once per second, even if the connection is + /// paused. + /// + /// The chance is high that you will get your write callback called before + /// this function returns. + pub fn unpause_read(&self) -> Result<(), Error> { + unsafe { + let rc = curl_sys::curl_easy_pause(self.inner.handle, + curl_sys::CURLPAUSE_RECV_CONT); + self.cvt(rc) + } + } + + /// Unpause writing on a connection. + /// + /// Using this function, you can explicitly unpause a connection that was + /// previously paused. + /// + /// A connection can be paused by letting the read or the write callbacks + /// return `ReadError::Pause` or `WriteError::Pause`. A write callback that + /// returns pause signals to the library that it couldn't take care of any + /// data at all, and that data will then be delivered again to the callback + /// when the writing is later unpaused. + /// + /// To unpause, you may for example call this from the progress callback + /// which gets called at least once per second, even if the connection is + /// paused. + pub fn unpause_write(&self) -> Result<(), Error> { + unsafe { + let rc = curl_sys::curl_easy_pause(self.inner.handle, + curl_sys::CURLPAUSE_SEND_CONT); + self.cvt(rc) + } + } + + /// URL encodes a string `s` + pub fn url_encode(&mut self, s: &[u8]) -> String { + if s.len() == 0 { + return String::new() + } + unsafe { + let p = curl_sys::curl_easy_escape(self.inner.handle, + s.as_ptr() as *const _, + s.len() as c_int); + assert!(!p.is_null()); + let ret = str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap(); + let ret = String::from(ret); + curl_sys::curl_free(p as *mut _); + return ret + } + } + + /// URL decodes a string `s`, returning `None` if it fails + pub fn url_decode(&mut self, s: &str) -> Vec { + if s.len() == 0 { + return Vec::new(); + } + + // Work around https://curl.haxx.se/docs/adv_20130622.html, a bug where + // if the last few characters are a bad escape then curl will have a + // buffer overrun. + let mut iter = s.chars().rev(); + let orig_len = s.len(); + let mut data; + let mut s = s; + if iter.next() == Some('%') || + iter.next() == Some('%') || + iter.next() == Some('%') { + data = s.to_string(); + data.push(0u8 as char); + s = &data[..]; + } + unsafe { + let mut len = 0; + let p = curl_sys::curl_easy_unescape(self.inner.handle, + s.as_ptr() as *const _, + orig_len as c_int, + &mut len); + assert!(!p.is_null()); + let slice = slice::from_raw_parts(p as *const u8, len as usize); + let ret = slice.to_vec(); + curl_sys::curl_free(p as *mut _); + return ret + } + } + + // TODO: I don't think this is safe, you can drop this which has all the + // callback data and then the next is use-after-free + // + // /// Attempts to clone this handle, returning a new session handle with the + // /// same options set for this handle. + // /// + // /// Internal state info and things like persistent connections ccannot be + // /// transferred. + // /// + // /// # Errors + // /// + // /// If a new handle could not be allocated or another error happens, `None` + // /// is returned. + // pub fn try_clone<'b>(&mut self) -> Option> { + // unsafe { + // let handle = curl_sys::curl_easy_duphandle(self.handle); + // if handle.is_null() { + // None + // } else { + // Some(Easy { + // handle: handle, + // data: blank_data(), + // _marker: marker::PhantomData, + // }) + // } + // } + // } + + /// Receives data from a connected socket. + /// + /// Only useful after a successful `perform` with the `connect_only` option + /// set as well. + pub fn recv(&mut self, data: &mut [u8]) -> Result { + unsafe { + let mut n = 0; + let r = curl_sys::curl_easy_recv(self.inner.handle, + data.as_mut_ptr() as *mut _, + data.len(), + &mut n); + if r == curl_sys::CURLE_OK { + Ok(n) + } else { + Err(Error::new(r)) + } + } + } + + /// Sends data over the connected socket. + /// + /// Only useful after a successful `perform` with the `connect_only` option + /// set as well. + pub fn send(&mut self, data: &[u8]) -> Result { + unsafe { + let mut n = 0; + let rc = curl_sys::curl_easy_send(self.inner.handle, + data.as_ptr() as *const _, + data.len(), + &mut n); + try!(self.cvt(rc)); + Ok(n) + } + } + + /// Get a pointer to the raw underlying CURL handle. + pub fn raw(&self) -> *mut curl_sys::CURL { + self.inner.handle + } + + #[cfg(unix)] + fn setopt_path(&mut self, + opt: curl_sys::CURLoption, + val: &Path) -> Result<(), Error> { + use std::os::unix::prelude::*; + let s = try!(CString::new(val.as_os_str().as_bytes())); + self.setopt_str(opt, &s) + } + + #[cfg(windows)] + fn setopt_path(&mut self, + opt: curl_sys::CURLoption, + val: &Path) -> Result<(), Error> { + match val.to_str() { + Some(s) => self.setopt_str(opt, &try!(CString::new(s))), + None => Err(Error::new(curl_sys::CURLE_CONV_FAILED)), + } + } + + fn setopt_long(&mut self, + opt: curl_sys::CURLoption, + val: c_long) -> Result<(), Error> { + unsafe { + self.cvt(curl_sys::curl_easy_setopt(self.inner.handle, opt, val)) + } + } + + fn setopt_str(&mut self, + opt: curl_sys::CURLoption, + val: &CStr) -> Result<(), Error> { + self.setopt_ptr(opt, val.as_ptr()) + } + + fn setopt_ptr(&self, + opt: curl_sys::CURLoption, + val: *const c_char) -> Result<(), Error> { + unsafe { + self.cvt(curl_sys::curl_easy_setopt(self.inner.handle, opt, val)) + } + } + + fn setopt_off_t(&mut self, + opt: curl_sys::CURLoption, + val: curl_sys::curl_off_t) -> Result<(), Error> { + unsafe { + let rc = curl_sys::curl_easy_setopt(self.inner.handle, opt, val); + self.cvt(rc) + } + } + + fn getopt_bytes(&mut self, opt: curl_sys::CURLINFO) + -> Result, Error> { + unsafe { + let p = try!(self.getopt_ptr(opt)); + if p.is_null() { + Ok(None) + } else { + Ok(Some(CStr::from_ptr(p).to_bytes())) + } + } + } + + fn getopt_ptr(&mut self, opt: curl_sys::CURLINFO) + -> Result<*const c_char, Error> { + unsafe { + let mut p = 0 as *const c_char; + let rc = curl_sys::curl_easy_getinfo(self.inner.handle, opt, &mut p); + try!(self.cvt(rc)); + Ok(p) + } + } + + fn getopt_str(&mut self, opt: curl_sys::CURLINFO) + -> Result, Error> { + match self.getopt_bytes(opt) { + Ok(None) => Ok(None), + Err(e) => Err(e), + Ok(Some(bytes)) => { + match str::from_utf8(bytes) { + Ok(s) => Ok(Some(s)), + Err(_) => Err(Error::new(curl_sys::CURLE_CONV_FAILED)), + } + } + } + } + + fn getopt_long(&mut self, opt: curl_sys::CURLINFO) -> Result { + unsafe { + let mut p = 0; + let rc = curl_sys::curl_easy_getinfo(self.inner.handle, opt, &mut p); + try!(self.cvt(rc)); + Ok(p) + } + } + + fn getopt_double(&mut self, opt: curl_sys::CURLINFO) -> Result { + unsafe { + let mut p = 0 as c_double; + let rc = curl_sys::curl_easy_getinfo(self.inner.handle, opt, &mut p); + try!(self.cvt(rc)); + Ok(p) + } + } + + fn cvt(&self, rc: curl_sys::CURLcode) -> Result<(), Error> { + if rc == curl_sys::CURLE_OK { + return Ok(()) + } + let mut buf = self.inner.error_buf.borrow_mut(); + if buf[0] == 0 { + return Err(Error::new(rc)) + } + let pos = buf.iter().position(|i| *i == 0).unwrap_or(buf.len()); + let msg = String::from_utf8_lossy(&buf[..pos]).into_owned(); + buf[0] = 0; + Err(::error::error_with_extra(rc, msg.into_boxed_str())) + } +} + +impl fmt::Debug for Easy2 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Easy") + .field("handle", &self.inner.handle) + .field("handler", &self.inner.handle) + .finish() + } +} + +impl Drop for Easy2 { + fn drop(&mut self) { + unsafe { + curl_sys::curl_easy_cleanup(self.inner.handle); + } + } +} + +extern fn header_cb(buffer: *mut c_char, + size: size_t, + nitems: size_t, + userptr: *mut c_void) -> size_t { + let keep_going = panic::catch(|| unsafe { + let data = slice::from_raw_parts(buffer as *const u8, + size * nitems); + (*(userptr as *mut Inner)).handler.header(data) + }).unwrap_or(false); + if keep_going { + size * nitems + } else { + !0 + } +} + +extern fn write_cb(ptr: *mut c_char, + size: size_t, + nmemb: size_t, + data: *mut c_void) -> size_t { + panic::catch(|| unsafe { + let input = slice::from_raw_parts(ptr as *const u8, + size * nmemb); + match (*(data as *mut Inner)).handler.write(input) { + Ok(s) => s, + Err(WriteError::Pause) | + Err(WriteError::__Nonexhaustive) => curl_sys::CURL_WRITEFUNC_PAUSE, + } + }).unwrap_or(!0) +} + +extern fn read_cb(ptr: *mut c_char, + size: size_t, + nmemb: size_t, + data: *mut c_void) -> size_t { + panic::catch(|| unsafe { + let input = slice::from_raw_parts_mut(ptr as *mut u8, + size * nmemb); + match (*(data as *mut Inner)).handler.read(input) { + Ok(s) => s, + Err(ReadError::Pause) => { + curl_sys::CURL_READFUNC_PAUSE + } + Err(ReadError::__Nonexhaustive) | + Err(ReadError::Abort) => { + curl_sys::CURL_READFUNC_ABORT + } + } + }).unwrap_or(!0) +} + +extern fn seek_cb(data: *mut c_void, + offset: curl_sys::curl_off_t, + origin: c_int) -> c_int { + panic::catch(|| unsafe { + let from = if origin == libc::SEEK_SET { + SeekFrom::Start(offset as u64) + } else { + panic!("unknown origin from libcurl: {}", origin); + }; + (*(data as *mut Inner)).handler.seek(from) as c_int + }).unwrap_or(!0) +} + +extern fn progress_cb(data: *mut c_void, + dltotal: c_double, + dlnow: c_double, + ultotal: c_double, + ulnow: c_double) -> c_int { + let keep_going = panic::catch(|| unsafe { + (*(data as *mut Inner)).handler.progress(dltotal, dlnow, ultotal, ulnow) + }).unwrap_or(false); + if keep_going { + 0 + } else { + 1 + } +} + +// TODO: expose `handle`? is that safe? +extern fn debug_cb(_handle: *mut curl_sys::CURL, + kind: curl_sys::curl_infotype, + data: *mut c_char, + size: size_t, + userptr: *mut c_void) -> c_int { + panic::catch(|| unsafe { + let data = slice::from_raw_parts(data as *const u8, size); + let kind = match kind { + curl_sys::CURLINFO_TEXT => InfoType::Text, + curl_sys::CURLINFO_HEADER_IN => InfoType::HeaderIn, + curl_sys::CURLINFO_HEADER_OUT => InfoType::HeaderOut, + curl_sys::CURLINFO_DATA_IN => InfoType::DataIn, + curl_sys::CURLINFO_DATA_OUT => InfoType::DataOut, + curl_sys::CURLINFO_SSL_DATA_IN => InfoType::SslDataIn, + curl_sys::CURLINFO_SSL_DATA_OUT => InfoType::SslDataOut, + _ => return, + }; + (*(userptr as *mut Inner)).handler.debug(kind, data) + }); + return 0 +} + +extern fn ssl_ctx_cb(_handle: *mut curl_sys::CURL, + ssl_ctx: *mut c_void, + data: *mut c_void) -> curl_sys::CURLcode { + let res = panic::catch(|| unsafe { + match (*(data as *mut Inner)).handler.ssl_ctx(ssl_ctx) { + Ok(()) => curl_sys::CURLE_OK, + Err(e) => e.code(), + } + }); + // Default to a generic SSL error in case of panic. This + // shouldn't really matter since the error should be + // propagated later on but better safe than sorry... + res.unwrap_or(curl_sys::CURLE_SSL_CONNECT_ERROR) +} + +// TODO: expose `purpose` and `sockaddr` inside of `address` +extern fn opensocket_cb(data: *mut c_void, + _purpose: curl_sys::curlsocktype, + address: *mut curl_sys::curl_sockaddr) + -> curl_sys::curl_socket_t +{ + let res = panic::catch(|| unsafe { + (*(data as *mut Inner)).handler.open_socket((*address).family, + (*address).socktype, + (*address).protocol) + .unwrap_or(curl_sys::CURL_SOCKET_BAD) + }); + res.unwrap_or(curl_sys::CURL_SOCKET_BAD) +} + +fn double_seconds_to_duration(seconds: f64) -> Duration { + let whole_seconds = seconds.trunc() as u64; + let nanos = seconds.fract() * 1_000_000_000f64; + Duration::new(whole_seconds, nanos as u32) +} + +#[test] +fn double_seconds_to_duration_whole_second() { + let dur = double_seconds_to_duration(1.0); + assert_eq!(dur.as_secs(), 1); + assert_eq!(dur.subsec_nanos(), 0); +} + +#[test] +fn double_seconds_to_duration_sub_second1() { + let dur = double_seconds_to_duration(0.0); + assert_eq!(dur.as_secs(), 0); + assert_eq!(dur.subsec_nanos(), 0); +} + +#[test] +fn double_seconds_to_duration_sub_second2() { + let dur = double_seconds_to_duration(0.5); + assert_eq!(dur.as_secs(), 0); + assert_eq!(dur.subsec_nanos(), 500_000_000); +} + +impl Auth { + /// Creates a new set of authentications with no members. + /// + /// An `Auth` structure is used to configure which forms of authentication + /// are attempted when negotiating connections with servers. + pub fn new() -> Auth { + Auth { bits: 0 } + } + + /// HTTP Basic authentication. + /// + /// This is the default choice, and the only method that is in wide-spread + /// use and supported virtually everywhere. This sends the user name and + /// password over the network in plain text, easily captured by others. + pub fn basic(&mut self, on: bool) -> &mut Auth { + self.flag(curl_sys::CURLAUTH_BASIC, on) + } + + /// HTTP Digest authentication. + /// + /// Digest authentication is defined in RFC 2617 and is a more secure way to + /// do authentication over public networks than the regular old-fashioned + /// Basic method. + pub fn digest(&mut self, on: bool) -> &mut Auth { + self.flag(curl_sys::CURLAUTH_DIGEST, on) + } + + /// HTTP Digest authentication with an IE flavor. + /// + /// Digest authentication is defined in RFC 2617 and is a more secure way to + /// do authentication over public networks than the regular old-fashioned + /// Basic method. The IE flavor is simply that libcurl will use a special + /// "quirk" that IE is known to have used before version 7 and that some + /// servers require the client to use. + pub fn digest_ie(&mut self, on: bool) -> &mut Auth { + self.flag(curl_sys::CURLAUTH_DIGEST_IE, on) + } + + /// HTTP Negotiate (SPNEGO) authentication. + /// + /// Negotiate authentication is defined in RFC 4559 and is the most secure + /// way to perform authentication over HTTP. + /// + /// You need to build libcurl with a suitable GSS-API library or SSPI on + /// Windows for this to work. + pub fn gssnegotiate(&mut self, on: bool) -> &mut Auth { + self.flag(curl_sys::CURLAUTH_GSSNEGOTIATE, on) + } + + /// HTTP NTLM authentication. + /// + /// A proprietary protocol invented and used by Microsoft. It uses a + /// challenge-response and hash concept similar to Digest, to prevent the + /// password from being eavesdropped. + /// + /// You need to build libcurl with either OpenSSL, GnuTLS or NSS support for + /// this option to work, or build libcurl on Windows with SSPI support. + pub fn ntlm(&mut self, on: bool) -> &mut Auth { + self.flag(curl_sys::CURLAUTH_NTLM, on) + } + + /// NTLM delegating to winbind helper. + /// + /// Authentication is performed by a separate binary application that is + /// executed when needed. The name of the application is specified at + /// compile time but is typically /usr/bin/ntlm_auth + /// + /// Note that libcurl will fork when necessary to run the winbind + /// application and kill it when complete, calling waitpid() to await its + /// exit when done. On POSIX operating systems, killing the process will + /// cause a SIGCHLD signal to be raised (regardless of whether + /// CURLOPT_NOSIGNAL is set), which must be handled intelligently by the + /// application. In particular, the application must not unconditionally + /// call wait() in its SIGCHLD signal handler to avoid being subject to a + /// race condition. This behavior is subject to change in future versions of + /// libcurl. + /// + /// A proprietary protocol invented and used by Microsoft. It uses a + /// challenge-response and hash concept similar to Digest, to prevent the + /// password from being eavesdropped. + pub fn ntlm_wb(&mut self, on: bool) -> &mut Auth { + self.flag(curl_sys::CURLAUTH_NTLM_WB, on) + } + + fn flag(&mut self, bit: c_ulong, on: bool) -> &mut Auth { + if on { + self.bits |= bit as c_long; + } else { + self.bits &= !bit as c_long; + } + self + } +} + +impl fmt::Debug for Auth { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let bits = self.bits as c_ulong; + f.debug_struct("Auth") + .field("basic", &(bits & curl_sys::CURLAUTH_BASIC != 0)) + .field("digest", &(bits & curl_sys::CURLAUTH_DIGEST != 0)) + .field("digest_ie", &(bits & curl_sys::CURLAUTH_DIGEST_IE != 0)) + .field("gssnegotiate", &(bits & curl_sys::CURLAUTH_GSSNEGOTIATE != 0)) + .field("ntlm", &(bits & curl_sys::CURLAUTH_NTLM != 0)) + .field("ntlm_wb", &(bits & curl_sys::CURLAUTH_NTLM_WB != 0)) + .finish() + } +} + +impl SslOpt { + /// Creates a new set of SSL options. + pub fn new() -> SslOpt { + SslOpt { bits: 0 } + } + + /// Tells libcurl to disable certificate revocation checks for those SSL + /// backends where such behavior is present. + /// + /// Currently this option is only supported for WinSSL (the native Windows + /// SSL library), with an exception in the case of Windows' Untrusted + /// Publishers blacklist which it seems can't be bypassed. This option may + /// have broader support to accommodate other SSL backends in the future. + /// https://curl.haxx.se/docs/ssl-compared.html + pub fn no_revoke(&mut self, on: bool) -> &mut SslOpt { + self.flag(curl_sys::CURLSSLOPT_NO_REVOKE, on) + } + + /// Tells libcurl to not attempt to use any workarounds for a security flaw + /// in the SSL3 and TLS1.0 protocols. + /// + /// If this option isn't used or this bit is set to 0, the SSL layer libcurl + /// uses may use a work-around for this flaw although it might cause + /// interoperability problems with some (older) SSL implementations. + /// + /// > WARNING: avoiding this work-around lessens the security, and by + /// > setting this option to 1 you ask for exactly that. This option is only + /// > supported for DarwinSSL, NSS and OpenSSL. + pub fn allow_beast(&mut self, on: bool) -> &mut SslOpt { + self.flag(curl_sys::CURLSSLOPT_ALLOW_BEAST, on) + } + + fn flag(&mut self, bit: c_long, on: bool) -> &mut SslOpt { + if on { + self.bits |= bit as c_long; + } else { + self.bits &= !bit as c_long; + } + self + } +} + +impl fmt::Debug for SslOpt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SslOpt") + .field("no_revoke", &(self.bits & curl_sys::CURLSSLOPT_NO_REVOKE != 0)) + .field("allow_beast", &(self.bits & curl_sys::CURLSSLOPT_ALLOW_BEAST != 0)) + .finish() + } +} diff --git a/curl-0.4.11/src/easy/list.rs b/curl-0.4.11/src/easy/list.rs new file mode 100644 index 000000000..732d00639 --- /dev/null +++ b/curl-0.4.11/src/easy/list.rs @@ -0,0 +1,99 @@ +use std::ffi::{CStr, CString}; +use std::fmt; + +use curl_sys; +use Error; + +/// A linked list of a strings +pub struct List { + raw: *mut curl_sys::curl_slist, +} + +/// An iterator over `List` +#[derive(Clone)] +pub struct Iter<'a> { + _me: &'a List, + cur: *mut curl_sys::curl_slist, +} + +pub fn raw(list: &List) -> *mut curl_sys::curl_slist { + list.raw +} + +pub unsafe fn from_raw(raw: *mut curl_sys::curl_slist) -> List { + List { raw: raw } +} + +unsafe impl Send for List {} + +impl List { + /// Creates a new empty list of strings. + pub fn new() -> List { + List { raw: 0 as *mut _ } + } + + /// Appends some data into this list. + pub fn append(&mut self, data: &str) -> Result<(), Error> { + let data = try!(CString::new(data)); + unsafe { + let raw = curl_sys::curl_slist_append(self.raw, data.as_ptr()); + assert!(!raw.is_null()); + self.raw = raw; + Ok(()) + } + } + + /// Returns an iterator over the nodes in this list. + pub fn iter(&self) -> Iter { + Iter { _me: self, cur: self.raw } + } +} + +impl fmt::Debug for List { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.iter().map(String::from_utf8_lossy)) + .finish() + } +} + +impl<'a> IntoIterator for &'a List { + type IntoIter = Iter<'a>; + type Item = &'a [u8]; + + fn into_iter(self) -> Iter<'a> { + self.iter() + } +} + +impl Drop for List { + fn drop(&mut self) { + unsafe { + curl_sys::curl_slist_free_all(self.raw) + } + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option<&'a [u8]> { + if self.cur.is_null() { + return None + } + + unsafe { + let ret = Some(CStr::from_ptr((*self.cur).data).to_bytes()); + self.cur = (*self.cur).next; + return ret + } + } +} + +impl<'a> fmt::Debug for Iter<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.clone().map(String::from_utf8_lossy)) + .finish() + } +} diff --git a/curl-0.4.11/src/easy/mod.rs b/curl-0.4.11/src/easy/mod.rs new file mode 100644 index 000000000..da8db0037 --- /dev/null +++ b/curl-0.4.11/src/easy/mod.rs @@ -0,0 +1,22 @@ +//! Bindings to the "easy" libcurl API. +//! +//! This module contains some simple types like `Easy` and `List` which are just +//! wrappers around the corresponding libcurl types. There's also a few enums +//! scattered about for various options here and there. +//! +//! Most simple usage of libcurl will likely use the `Easy` structure here, and +//! you can find more docs about its usage on that struct. + +mod list; +mod form; +mod handle; +mod handler; +mod windows; + +pub use self::list::{List, Iter}; +pub use self::form::{Form, Part}; +pub use self::handle::{Easy, Transfer}; +pub use self::handler::{Easy2, Handler}; +pub use self::handler::{InfoType, SeekResult, ReadError, WriteError}; +pub use self::handler::{TimeCondition, IpResolve, HttpVersion, SslVersion}; +pub use self::handler::{SslOpt, NetRc, Auth, ProxyType}; diff --git a/curl-0.4.11/src/easy/windows.rs b/curl-0.4.11/src/easy/windows.rs new file mode 100644 index 000000000..018e3dba2 --- /dev/null +++ b/curl-0.4.11/src/easy/windows.rs @@ -0,0 +1,136 @@ +#![allow(non_camel_case_types, non_snake_case)] + +use libc::c_void; + +#[cfg(target_env = "msvc")] +mod win { + use kernel32; + use std::ffi::CString; + use std::mem; + use std::ptr; + use schannel::cert_context::ValidUses; + use schannel::cert_store::CertStore; + use winapi::{self, c_void, c_uchar, c_long, c_int}; + + fn lookup(module: &str, symbol: &str) -> Option<*const c_void> { + unsafe { + let symbol = CString::new(symbol).unwrap(); + let mut mod_buf: Vec = module.encode_utf16().collect(); + mod_buf.push(0); + let handle = kernel32::GetModuleHandleW(mod_buf.as_mut_ptr()); + let n = kernel32::GetProcAddress(handle, symbol.as_ptr()); + if n == ptr::null() { + None + } else { + Some(n) + } + } + } + + pub enum X509_STORE {} + pub enum X509 {} + pub enum SSL_CTX {} + + type d2i_X509_fn = unsafe extern "C" fn( + a: *mut *mut X509, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut X509; + type X509_free_fn = unsafe extern "C" fn(x: *mut X509); + type X509_STORE_add_cert_fn = unsafe extern "C" fn(store: *mut X509_STORE, x: *mut X509) + -> c_int; + type SSL_CTX_get_cert_store_fn = unsafe extern "C" fn(ctx: *const SSL_CTX) + -> *mut X509_STORE; + + struct OpenSSL { + d2i_X509: d2i_X509_fn, + X509_free: X509_free_fn, + X509_STORE_add_cert: X509_STORE_add_cert_fn, + SSL_CTX_get_cert_store: SSL_CTX_get_cert_store_fn, + } + + unsafe fn lookup_functions(crypto_module: &str, ssl_module: &str) + -> Option + { + macro_rules! get { + ($(let $sym:ident in $module:expr;)*) => ($( + let $sym = match lookup($module, stringify!($sym)) { + Some(p) => p, + None => return None, + }; + )*) + } + get! { + let d2i_X509 in crypto_module; + let X509_free in crypto_module; + let X509_STORE_add_cert in crypto_module; + let SSL_CTX_get_cert_store in ssl_module; + } + Some(OpenSSL { + d2i_X509: mem::transmute(d2i_X509), + X509_free: mem::transmute(X509_free), + X509_STORE_add_cert: mem::transmute(X509_STORE_add_cert), + SSL_CTX_get_cert_store: mem::transmute(SSL_CTX_get_cert_store), + }) + } + + pub unsafe fn add_certs_to_context(ssl_ctx: *mut c_void) { + // check the runtime version of OpenSSL + let openssl = match ::version::Version::get().ssl_version() { + Some(ssl_ver) if ssl_ver.starts_with("OpenSSL/1.1.0") => { + lookup_functions("libcrypto", "libssl") + } + Some(ssl_ver) if ssl_ver.starts_with("OpenSSL/1.0.2") => { + lookup_functions("libeay32", "ssleay32") + } + _ => return, + }; + let openssl = match openssl { + Some(s) => s, + None => return, + }; + + let openssl_store = (openssl.SSL_CTX_get_cert_store)(ssl_ctx as *const SSL_CTX); + let mut store = match CertStore::open_current_user("ROOT") { + Ok(s) => s, + Err(_) => return, + }; + + for cert in store.certs() { + let valid_uses = match cert.valid_uses() { + Ok(v) => v, + Err(_) => continue, + }; + + // check the extended key usage for the "Server Authentication" OID + match valid_uses { + ValidUses::All => {} + ValidUses::Oids(ref oids) => { + let oid = winapi::wincrypt::szOID_PKIX_KP_SERVER_AUTH.to_owned(); + if !oids.contains(&oid) { + continue + } + } + } + + let der = cert.to_der(); + let x509 = (openssl.d2i_X509)(ptr::null_mut(), + &mut der.as_ptr(), + der.len() as c_long); + if !x509.is_null() { + (openssl.X509_STORE_add_cert)(openssl_store, x509); + (openssl.X509_free)(x509); + } + } + } +} + +#[cfg(target_env = "msvc")] +pub fn add_certs_to_context(ssl_ctx: *mut c_void) { + unsafe { + win::add_certs_to_context(ssl_ctx as *mut _); + } +} + +#[cfg(not(target_env = "msvc"))] +pub fn add_certs_to_context(_: *mut c_void) {} diff --git a/curl-0.4.11/src/error.rs b/curl-0.4.11/src/error.rs new file mode 100644 index 000000000..8dacc2b49 --- /dev/null +++ b/curl-0.4.11/src/error.rs @@ -0,0 +1,598 @@ +use std::error; +use std::ffi::{self, CStr}; +use std::fmt; +use std::str; +use std::io; + +use curl_sys; + +/// An error returned from various "easy" operations. +/// +/// This structure wraps a `CURLcode`. +#[derive(Clone, PartialEq)] +pub struct Error { + code: curl_sys::CURLcode, + extra: Option>, +} + +pub fn error_with_extra(code: curl_sys::CURLcode, extra: Box) -> Error { + Error { + code: code, + extra: Some(extra), + } +} + +impl Error { + /// Creates a new error from the underlying code returned by libcurl. + pub fn new(code: curl_sys::CURLcode) -> Error { + Error { + code: code, + extra: None, + } + } + + /// Returns whether this error corresponds to CURLE_UNSUPPORTED_PROTOCOL. + pub fn is_unsupported_protocol(&self) -> bool { + self.code == curl_sys::CURLE_UNSUPPORTED_PROTOCOL + } + + /// Returns whether this error corresponds to CURLE_FAILED_INIT. + pub fn is_failed_init(&self) -> bool { + self.code == curl_sys::CURLE_FAILED_INIT + } + + /// Returns whether this error corresponds to CURLE_URL_MALFORMAT. + pub fn is_url_malformed(&self) -> bool { + self.code == curl_sys::CURLE_URL_MALFORMAT + } + + // /// Returns whether this error corresponds to CURLE_NOT_BUILT_IN. + // pub fn is_not_built_in(&self) -> bool { + // self.code == curl_sys::CURLE_NOT_BUILT_IN + // } + + /// Returns whether this error corresponds to CURLE_COULDNT_RESOLVE_PROXY. + pub fn is_couldnt_resolve_proxy(&self) -> bool { + self.code == curl_sys::CURLE_COULDNT_RESOLVE_PROXY + } + + /// Returns whether this error corresponds to CURLE_COULDNT_RESOLVE_HOST. + pub fn is_couldnt_resolve_host(&self) -> bool { + self.code == curl_sys::CURLE_COULDNT_RESOLVE_HOST + } + + /// Returns whether this error corresponds to CURLE_COULDNT_CONNECT. + pub fn is_couldnt_connect(&self) -> bool { + self.code == curl_sys::CURLE_COULDNT_CONNECT + } + + /// Returns whether this error corresponds to CURLE_REMOTE_ACCESS_DENIED. + pub fn is_remote_access_denied(&self) -> bool { + self.code == curl_sys::CURLE_REMOTE_ACCESS_DENIED + } + + /// Returns whether this error corresponds to CURLE_PARTIAL_FILE. + pub fn is_partial_file(&self) -> bool { + self.code == curl_sys::CURLE_PARTIAL_FILE + } + + /// Returns whether this error corresponds to CURLE_QUOTE_ERROR. + pub fn is_quote_error(&self) -> bool { + self.code == curl_sys::CURLE_QUOTE_ERROR + } + + /// Returns whether this error corresponds to CURLE_HTTP_RETURNED_ERROR. + pub fn is_http_returned_error(&self) -> bool { + self.code == curl_sys::CURLE_HTTP_RETURNED_ERROR + } + + /// Returns whether this error corresponds to CURLE_READ_ERROR. + pub fn is_read_error(&self) -> bool { + self.code == curl_sys::CURLE_READ_ERROR + } + + /// Returns whether this error corresponds to CURLE_WRITE_ERROR. + pub fn is_write_error(&self) -> bool { + self.code == curl_sys::CURLE_WRITE_ERROR + } + + /// Returns whether this error corresponds to CURLE_UPLOAD_FAILED. + pub fn is_upload_failed(&self) -> bool { + self.code == curl_sys::CURLE_UPLOAD_FAILED + } + + /// Returns whether this error corresponds to CURLE_OUT_OF_MEMORY. + pub fn is_out_of_memory(&self) -> bool { + self.code == curl_sys::CURLE_OUT_OF_MEMORY + } + + /// Returns whether this error corresponds to CURLE_OPERATION_TIMEDOUT. + pub fn is_operation_timedout(&self) -> bool { + self.code == curl_sys::CURLE_OPERATION_TIMEDOUT + } + + /// Returns whether this error corresponds to CURLE_RANGE_ERROR. + pub fn is_range_error(&self) -> bool { + self.code == curl_sys::CURLE_RANGE_ERROR + } + + /// Returns whether this error corresponds to CURLE_HTTP_POST_ERROR. + pub fn is_http_post_error(&self) -> bool { + self.code == curl_sys::CURLE_HTTP_POST_ERROR + } + + /// Returns whether this error corresponds to CURLE_SSL_CONNECT_ERROR. + pub fn is_ssl_connect_error(&self) -> bool { + self.code == curl_sys::CURLE_SSL_CONNECT_ERROR + } + + /// Returns whether this error corresponds to CURLE_BAD_DOWNLOAD_RESUME. + pub fn is_bad_download_resume(&self) -> bool { + self.code == curl_sys::CURLE_BAD_DOWNLOAD_RESUME + } + + /// Returns whether this error corresponds to CURLE_FILE_COULDNT_READ_FILE. + pub fn is_file_couldnt_read_file(&self) -> bool { + self.code == curl_sys::CURLE_FILE_COULDNT_READ_FILE + } + + /// Returns whether this error corresponds to CURLE_FUNCTION_NOT_FOUND. + pub fn is_function_not_found(&self) -> bool { + self.code == curl_sys::CURLE_FUNCTION_NOT_FOUND + } + + /// Returns whether this error corresponds to CURLE_ABORTED_BY_CALLBACK. + pub fn is_aborted_by_callback(&self) -> bool { + self.code == curl_sys::CURLE_ABORTED_BY_CALLBACK + } + + /// Returns whether this error corresponds to CURLE_BAD_FUNCTION_ARGUMENT. + pub fn is_bad_function_argument(&self) -> bool { + self.code == curl_sys::CURLE_BAD_FUNCTION_ARGUMENT + } + + /// Returns whether this error corresponds to CURLE_INTERFACE_FAILED. + pub fn is_interface_failed(&self) -> bool { + self.code == curl_sys::CURLE_INTERFACE_FAILED + } + + /// Returns whether this error corresponds to CURLE_TOO_MANY_REDIRECTS. + pub fn is_too_many_redirects(&self) -> bool { + self.code == curl_sys::CURLE_TOO_MANY_REDIRECTS + } + + /// Returns whether this error corresponds to CURLE_UNKNOWN_OPTION. + pub fn is_unknown_option(&self) -> bool { + self.code == curl_sys::CURLE_UNKNOWN_OPTION + } + + /// Returns whether this error corresponds to CURLE_PEER_FAILED_VERIFICATION. + pub fn is_peer_failed_verification(&self) -> bool { + self.code == curl_sys::CURLE_PEER_FAILED_VERIFICATION + } + + /// Returns whether this error corresponds to CURLE_GOT_NOTHING. + pub fn is_got_nothing(&self) -> bool { + self.code == curl_sys::CURLE_GOT_NOTHING + } + + /// Returns whether this error corresponds to CURLE_SSL_ENGINE_NOTFOUND. + pub fn is_ssl_engine_notfound(&self) -> bool { + self.code == curl_sys::CURLE_SSL_ENGINE_NOTFOUND + } + + /// Returns whether this error corresponds to CURLE_SSL_ENGINE_SETFAILED. + pub fn is_ssl_engine_setfailed(&self) -> bool { + self.code == curl_sys::CURLE_SSL_ENGINE_SETFAILED + } + + /// Returns whether this error corresponds to CURLE_SEND_ERROR. + pub fn is_send_error(&self) -> bool { + self.code == curl_sys::CURLE_SEND_ERROR + } + + /// Returns whether this error corresponds to CURLE_RECV_ERROR. + pub fn is_recv_error(&self) -> bool { + self.code == curl_sys::CURLE_RECV_ERROR + } + + /// Returns whether this error corresponds to CURLE_SSL_CERTPROBLEM. + pub fn is_ssl_certproblem(&self) -> bool { + self.code == curl_sys::CURLE_SSL_CERTPROBLEM + } + + /// Returns whether this error corresponds to CURLE_SSL_CIPHER. + pub fn is_ssl_cipher(&self) -> bool { + self.code == curl_sys::CURLE_SSL_CIPHER + } + + /// Returns whether this error corresponds to CURLE_SSL_CACERT. + pub fn is_ssl_cacert(&self) -> bool { + self.code == curl_sys::CURLE_SSL_CACERT + } + + /// Returns whether this error corresponds to CURLE_BAD_CONTENT_ENCODING. + pub fn is_bad_content_encoding(&self) -> bool { + self.code == curl_sys::CURLE_BAD_CONTENT_ENCODING + } + + /// Returns whether this error corresponds to CURLE_FILESIZE_EXCEEDED. + pub fn is_filesize_exceeded(&self) -> bool { + self.code == curl_sys::CURLE_FILESIZE_EXCEEDED + } + + /// Returns whether this error corresponds to CURLE_USE_SSL_FAILED. + pub fn is_use_ssl_failed(&self) -> bool { + self.code == curl_sys::CURLE_USE_SSL_FAILED + } + + /// Returns whether this error corresponds to CURLE_SEND_FAIL_REWIND. + pub fn is_send_fail_rewind(&self) -> bool { + self.code == curl_sys::CURLE_SEND_FAIL_REWIND + } + + /// Returns whether this error corresponds to CURLE_SSL_ENGINE_INITFAILED. + pub fn is_ssl_engine_initfailed(&self) -> bool { + self.code == curl_sys::CURLE_SSL_ENGINE_INITFAILED + } + + /// Returns whether this error corresponds to CURLE_LOGIN_DENIED. + pub fn is_login_denied(&self) -> bool { + self.code == curl_sys::CURLE_LOGIN_DENIED + } + + /// Returns whether this error corresponds to CURLE_CONV_FAILED. + pub fn is_conv_failed(&self) -> bool { + self.code == curl_sys::CURLE_CONV_FAILED + } + + /// Returns whether this error corresponds to CURLE_CONV_REQD. + pub fn is_conv_required(&self) -> bool { + self.code == curl_sys::CURLE_CONV_REQD + } + + /// Returns whether this error corresponds to CURLE_SSL_CACERT_BADFILE. + pub fn is_ssl_cacert_badfile(&self) -> bool { + self.code == curl_sys::CURLE_SSL_CACERT_BADFILE + } + + /// Returns whether this error corresponds to CURLE_SSL_CRL_BADFILE. + pub fn is_ssl_crl_badfile(&self) -> bool { + self.code == curl_sys::CURLE_SSL_CRL_BADFILE + } + + /// Returns whether this error corresponds to CURLE_SSL_SHUTDOWN_FAILED. + pub fn is_ssl_shutdown_failed(&self) -> bool { + self.code == curl_sys::CURLE_SSL_SHUTDOWN_FAILED + } + + /// Returns whether this error corresponds to CURLE_AGAIN. + pub fn is_again(&self) -> bool { + self.code == curl_sys::CURLE_AGAIN + } + + /// Returns whether this error corresponds to CURLE_SSL_ISSUER_ERROR. + pub fn is_ssl_issuer_error(&self) -> bool { + self.code == curl_sys::CURLE_SSL_ISSUER_ERROR + } + + /// Returns whether this error corresponds to CURLE_CHUNK_FAILED. + pub fn is_chunk_failed(&self) -> bool { + self.code == curl_sys::CURLE_CHUNK_FAILED + } + + // /// Returns whether this error corresponds to CURLE_NO_CONNECTION_AVAILABLE. + // pub fn is_no_connection_available(&self) -> bool { + // self.code == curl_sys::CURLE_NO_CONNECTION_AVAILABLE + // } + + /// Returns the value of the underlying error corresponding to libcurl. + pub fn code(&self) -> curl_sys::CURLcode { + self.code + } + + /// Returns the extra description of this error, if any is available. + pub fn extra_description(&self) -> Option<&str> { + self.extra.as_ref().map(|s| &**s) + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let desc = error::Error::description(self); + match self.extra { + Some(ref s) => write!(f, "[{}] {} ({})", self.code(), desc, s), + None => write!(f, "[{}] {}", self.code(), desc), + } + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Error") + .field("description", &error::Error::description(self)) + .field("code", &self.code) + .field("extra", &self.extra) + .finish() + } +} + +impl error::Error for Error { + fn description(&self) -> &str { + unsafe { + let s = curl_sys::curl_easy_strerror(self.code); + assert!(!s.is_null()); + str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() + } + } +} + +/// An error returned from "share" operations. +/// +/// This structure wraps a `CURLSHcode`. +#[derive(Clone, PartialEq)] +pub struct ShareError { + code: curl_sys::CURLSHcode, +} + +impl ShareError { + /// Creates a new error from the underlying code returned by libcurl. + pub fn new(code: curl_sys::CURLSHcode) -> ShareError { + ShareError { code: code } + } + + /// Returns whether this error corresponds to CURLSHE_BAD_OPTION. + pub fn is_bad_option(&self) -> bool { + self.code == curl_sys::CURLSHE_BAD_OPTION + } + + /// Returns whether this error corresponds to CURLSHE_IN_USE. + pub fn is_in_use(&self) -> bool { + self.code == curl_sys::CURLSHE_IN_USE + } + + /// Returns whether this error corresponds to CURLSHE_INVALID. + pub fn is_invalid(&self) -> bool { + self.code == curl_sys::CURLSHE_INVALID + } + + /// Returns whether this error corresponds to CURLSHE_NOMEM. + pub fn is_nomem(&self) -> bool { + self.code == curl_sys::CURLSHE_NOMEM + } + + // /// Returns whether this error corresponds to CURLSHE_NOT_BUILT_IN. + // pub fn is_not_built_in(&self) -> bool { + // self.code == curl_sys::CURLSHE_NOT_BUILT_IN + // } + + /// Returns the value of the underlying error corresponding to libcurl. + pub fn code(&self) -> curl_sys::CURLSHcode { + self.code + } +} + +impl fmt::Display for ShareError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + error::Error::description(self).fmt(f) + } +} + +impl fmt::Debug for ShareError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ShareError {{ description: {:?}, code: {} }}", + error::Error::description(self), + self.code) + } +} + +impl error::Error for ShareError { + fn description(&self) -> &str { + unsafe { + let s = curl_sys::curl_share_strerror(self.code); + assert!(!s.is_null()); + str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() + } + } +} + +/// An error from "multi" operations. +/// +/// THis structure wraps a `CURLMcode`. +#[derive(Clone, PartialEq)] +pub struct MultiError { + code: curl_sys::CURLMcode, +} + +impl MultiError { + /// Creates a new error from the underlying code returned by libcurl. + pub fn new(code: curl_sys::CURLMcode) -> MultiError { + MultiError { code: code } + } + + /// Returns whether this error corresponds to CURLM_BAD_HANDLE. + pub fn is_bad_handle(&self) -> bool { + self.code == curl_sys::CURLM_BAD_HANDLE + } + + /// Returns whether this error corresponds to CURLM_BAD_EASY_HANDLE. + pub fn is_bad_easy_handle(&self) -> bool { + self.code == curl_sys::CURLM_BAD_EASY_HANDLE + } + + /// Returns whether this error corresponds to CURLM_OUT_OF_MEMORY. + pub fn is_out_of_memory(&self) -> bool { + self.code == curl_sys::CURLM_OUT_OF_MEMORY + } + + /// Returns whether this error corresponds to CURLM_INTERNAL_ERROR. + pub fn is_internal_error(&self) -> bool { + self.code == curl_sys::CURLM_INTERNAL_ERROR + } + + /// Returns whether this error corresponds to CURLM_BAD_SOCKET. + pub fn is_bad_socket(&self) -> bool { + self.code == curl_sys::CURLM_BAD_SOCKET + } + + /// Returns whether this error corresponds to CURLM_UNKNOWN_OPTION. + pub fn is_unknown_option(&self) -> bool { + self.code == curl_sys::CURLM_UNKNOWN_OPTION + } + + /// Returns whether this error corresponds to CURLM_CALL_MULTI_PERFORM. + pub fn is_call_perform(&self) -> bool { + self.code == curl_sys::CURLM_CALL_MULTI_PERFORM + } + + // /// Returns whether this error corresponds to CURLM_ADDED_ALREADY. + // pub fn is_added_already(&self) -> bool { + // self.code == curl_sys::CURLM_ADDED_ALREADY + // } + + /// Returns the value of the underlying error corresponding to libcurl. + pub fn code(&self) -> curl_sys::CURLMcode { + self.code + } +} + +impl fmt::Display for MultiError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + error::Error::description(self).fmt(f) + } +} + +impl fmt::Debug for MultiError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "MultiError {{ description: {:?}, code: {} }}", + error::Error::description(self), + self.code) + } +} + +impl error::Error for MultiError { + fn description(&self) -> &str { + unsafe { + let s = curl_sys::curl_multi_strerror(self.code); + assert!(!s.is_null()); + str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() + } + } +} + + +/// An error from "form add" operations. +/// +/// THis structure wraps a `CURLFORMcode`. +#[derive(Clone, PartialEq)] +pub struct FormError { + code: curl_sys::CURLFORMcode, +} + +impl FormError { + /// Creates a new error from the underlying code returned by libcurl. + pub fn new(code: curl_sys::CURLFORMcode) -> FormError { + FormError { code: code } + } + + /// Returns whether this error corresponds to CURL_FORMADD_MEMORY. + pub fn is_memory(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_MEMORY + } + + /// Returns whether this error corresponds to CURL_FORMADD_OPTION_TWICE. + pub fn is_option_twice(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_OPTION_TWICE + } + + /// Returns whether this error corresponds to CURL_FORMADD_NULL. + pub fn is_null(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_NULL + } + + /// Returns whether this error corresponds to CURL_FORMADD_UNKNOWN_OPTION. + pub fn is_unknown_option(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_UNKNOWN_OPTION + } + + /// Returns whether this error corresponds to CURL_FORMADD_INCOMPLETE. + pub fn is_incomplete(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_INCOMPLETE + } + + /// Returns whether this error corresponds to CURL_FORMADD_ILLEGAL_ARRAY. + pub fn is_illegal_array(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_ILLEGAL_ARRAY + } + + /// Returns whether this error corresponds to CURL_FORMADD_DISABLED. + pub fn is_disabled(&self) -> bool { + self.code == curl_sys::CURL_FORMADD_DISABLED + } + + /// Returns the value of the underlying error corresponding to libcurl. + pub fn code(&self) -> curl_sys::CURLFORMcode { + self.code + } +} + +impl fmt::Display for FormError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + error::Error::description(self).fmt(f) + } +} + +impl fmt::Debug for FormError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "FormError {{ description: {:?}, code: {} }}", + error::Error::description(self), + self.code) + } +} + +impl error::Error for FormError { + fn description(&self) -> &str { + match self.code { + curl_sys::CURL_FORMADD_MEMORY => "allocation failure", + curl_sys::CURL_FORMADD_OPTION_TWICE => "one option passed twice", + curl_sys::CURL_FORMADD_NULL => "null pointer given for string", + curl_sys::CURL_FORMADD_UNKNOWN_OPTION => "unknown option", + curl_sys::CURL_FORMADD_INCOMPLETE => "form information not complete", + curl_sys::CURL_FORMADD_ILLEGAL_ARRAY => "illegal array in option", + curl_sys::CURL_FORMADD_DISABLED => { + "libcurl does not have support for this option compiled in" + } + _ => "unknown form error", + } + } +} + +impl From for Error { + fn from(_: ffi::NulError) -> Error { + Error { code: curl_sys::CURLE_CONV_FAILED, extra: None } + } +} + +impl From for io::Error { + fn from(e: Error) -> io::Error { + io::Error::new(io::ErrorKind::Other, e) + } +} + +impl From for io::Error { + fn from(e: ShareError) -> io::Error { + io::Error::new(io::ErrorKind::Other, e) + } +} + +impl From for io::Error { + fn from(e: MultiError) -> io::Error { + io::Error::new(io::ErrorKind::Other, e) + } +} + +impl From for io::Error { + fn from(e: FormError) -> io::Error { + io::Error::new(io::ErrorKind::Other, e) + } +} diff --git a/curl-0.4.11/src/lib.rs b/curl-0.4.11/src/lib.rs new file mode 100644 index 000000000..94377249c --- /dev/null +++ b/curl-0.4.11/src/lib.rs @@ -0,0 +1,128 @@ +//! Rust bindings to the libcurl C library +//! +//! This crate contains bindings for an HTTP/HTTPS client which is powered by +//! [libcurl], the same library behind the `curl` command line tool. The API +//! currently closely matches that of libcurl itself, except that a Rustic layer +//! of safety is applied on top. +//! +//! [libcurl]: https://curl.haxx.se/libcurl/ +//! +//! # The "Easy" API +//! +//! The easiest way to send a request is to use the `Easy` api which corresponds +//! to `CURL` in libcurl. This handle supports a wide variety of options and can +//! be used to make a single blocking request in a thread. Callbacks can be +//! specified to deal with data as it arrives and a handle can be reused to +//! cache connections and such. +//! +//! ```rust,no_run +//! use std::io::{stdout, Write}; +//! +//! use curl::easy::Easy; +//! +//! // Write the contents of rust-lang.org to stdout +//! let mut easy = Easy::new(); +//! easy.url("https://www.rust-lang.org/").unwrap(); +//! easy.write_function(|data| { +//! Ok(stdout().write(data).unwrap()) +//! }).unwrap(); +//! easy.perform().unwrap(); +//! ``` +//! +//! # What about multiple concurrent HTTP requests? +//! +//! One option you have currently is to send multiple requests in multiple +//! threads, but otherwise libcurl has a "multi" interface for doing this +//! operation. Initial bindings of this interface can be found in the `multi` +//! module, but feedback is welcome! +//! +//! # Where does libcurl come from? +//! +//! This crate links to the `curl-sys` crate which is in turn responsible for +//! acquiring and linking to the libcurl library. Currently this crate will +//! build libcurl from source if one is not already detected on the system. +//! +//! There is a large number of releases for libcurl, all with different sets of +//! capabilities. Robust programs may wish to inspect `Version::get()` to test +//! what features are implemented in the linked build of libcurl at runtime. + +#![deny(missing_docs, missing_debug_implementations)] +#![doc(html_root_url = "https://docs.rs/curl/0.4")] + +extern crate curl_sys; +extern crate libc; +extern crate socket2; + +#[cfg(all(unix, not(target_os = "macos")))] +extern crate openssl_sys; +#[cfg(all(unix, not(target_os = "macos")))] +extern crate openssl_probe; +#[cfg(windows)] +extern crate winapi; + +#[cfg(target_env = "msvc")] +extern crate kernel32; +#[cfg(target_env = "msvc")] +extern crate schannel; + +use std::ffi::CStr; +use std::str; +use std::sync::{Once, ONCE_INIT}; + +pub use error::{Error, ShareError, MultiError, FormError}; +mod error; + +pub use version::{Version, Protocols}; +mod version; + +mod panic; +pub mod easy; +pub mod multi; + +/// Initializes the underlying libcurl library. +/// +/// It's not required to call this before the library is used, but it's +/// recommended to do so as soon as the program starts. +pub fn init() { + static INIT: Once = ONCE_INIT; + INIT.call_once(|| { + platform_init(); + unsafe { + assert_eq!(curl_sys::curl_global_init(curl_sys::CURL_GLOBAL_ALL), 0); + } + + // Note that we explicitly don't schedule a call to + // `curl_global_cleanup`. The documentation for that function says + // + // > You must not call it when any other thread in the program (i.e. a + // > thread sharing the same memory) is running. This doesn't just mean + // > no other thread that is using libcurl. + // + // We can't ever be sure of that, so unfortunately we can't call the + // function. + }); + + #[cfg(all(unix, not(target_os = "macos")))] + fn platform_init() { + openssl_sys::init(); + } + + #[cfg(not(all(unix, not(target_os = "macos"))))] + fn platform_init() {} +} + +unsafe fn opt_str<'a>(ptr: *const libc::c_char) -> Option<&'a str> { + if ptr.is_null() { + None + } else { + Some(str::from_utf8(CStr::from_ptr(ptr).to_bytes()).unwrap()) + } +} + +fn cvt(r: curl_sys::CURLcode) -> Result<(), Error> { + if r == curl_sys::CURLE_OK { + Ok(()) + } else { + Err(Error::new(r)) + } +} diff --git a/curl-0.4.11/src/multi.rs b/curl-0.4.11/src/multi.rs new file mode 100644 index 000000000..7f80631f5 --- /dev/null +++ b/curl-0.4.11/src/multi.rs @@ -0,0 +1,928 @@ +//! Multi - initiating multiple requests simultaneously + +use std::fmt; +use std::marker; +use std::time::Duration; + +use libc::{c_int, c_char, c_void, c_long, c_short}; +use curl_sys; + +#[cfg(windows)] +use winapi::winsock2::fd_set; +#[cfg(unix)] +use libc::{fd_set, pollfd, POLLIN, POLLPRI, POLLOUT}; + +use {MultiError, Error}; +use easy::{Easy, Easy2}; +use panic; + +/// A multi handle for initiating multiple connections simultaneously. +/// +/// This structure corresponds to `CURLM` in libcurl and provides the ability to +/// have multiple transfers in flight simultaneously. This handle is then used +/// to manage each transfer. The main purpose of a `CURLM` is for the +/// *application* to drive the I/O rather than libcurl itself doing all the +/// blocking. Methods like `action` allow the application to inform libcurl of +/// when events have happened. +/// +/// Lots more documentation can be found on the libcurl [multi tutorial] where +/// the APIs correspond pretty closely with this crate. +/// +/// [multi tutorial]: https://curl.haxx.se/libcurl/c/libcurl-multi.html +pub struct Multi { + raw: *mut curl_sys::CURLM, + data: Box, +} + +struct MultiData { + socket: Box, + timer: Box) -> bool + Send>, +} + +/// Message from the `messages` function of a multi handle. +/// +/// Currently only indicates whether a transfer is done. +pub struct Message<'multi> { + ptr: *mut curl_sys::CURLMsg, + _multi: &'multi Multi, +} + +/// Wrapper around an easy handle while it's owned by a multi handle. +/// +/// Once an easy handle has been added to a multi handle then it can no longer +/// be used via `perform`. This handle is also used to remove the easy handle +/// from the multi handle when desired. +pub struct EasyHandle { + easy: Easy, + // This is now effecitvely bound to a `Multi`, so it is no longer sendable. + _marker: marker::PhantomData<&'static Multi>, +} + +/// Wrapper around an easy handle while it's owned by a multi handle. +/// +/// Once an easy handle has been added to a multi handle then it can no longer +/// be used via `perform`. This handle is also used to remove the easy handle +/// from the multi handle when desired. +pub struct Easy2Handle { + easy: Easy2, + // This is now effecitvely bound to a `Multi`, so it is no longer sendable. + _marker: marker::PhantomData<&'static Multi>, +} + +/// Notification of the events that have happened on a socket. +/// +/// This type is passed as an argument to the `action` method on a multi handle +/// to indicate what events have occurred on a socket. +pub struct Events { + bits: c_int, +} + +/// Notification of events that are requested on a socket. +/// +/// This type is yielded to the `socket_function` callback to indicate what +/// events are requested on a socket. +pub struct SocketEvents { + bits: c_int, +} + +/// Raw underlying socket type that the multi handles use +pub type Socket = curl_sys::curl_socket_t; + +/// File descriptor to wait on for use with the `wait` method on a multi handle. +pub struct WaitFd { + inner: curl_sys::curl_waitfd, +} + +impl Multi { + /// Creates a new multi session through which multiple HTTP transfers can be + /// initiated. + pub fn new() -> Multi { + unsafe { + ::init(); + let ptr = curl_sys::curl_multi_init(); + assert!(!ptr.is_null()); + Multi { + raw: ptr, + data: Box::new(MultiData { + socket: Box::new(|_, _, _| ()), + timer: Box::new(|_| true), + }), + } + } + } + + /// Set the callback informed about what to wait for + /// + /// When the `action` function runs, it informs the application about + /// updates in the socket (file descriptor) status by doing none, one, or + /// multiple calls to the socket callback. The callback gets status updates + /// with changes since the previous time the callback was called. See + /// `action` for more details on how the callback is used and should work. + /// + /// The `SocketEvents` parameter informs the callback on the status of the + /// given socket, and the methods on that type can be used to learn about + /// what's going on with the socket. + /// + /// The third `usize` parameter is a custom value set by the `assign` method + /// below. + pub fn socket_function(&mut self, f: F) -> Result<(), MultiError> + where F: FnMut(Socket, SocketEvents, usize) + Send + 'static, + { + self._socket_function(Box::new(f)) + } + + fn _socket_function(&mut self, + f: Box) + -> Result<(), MultiError> + { + self.data.socket = f; + let cb: curl_sys::curl_socket_callback = cb; + try!(self.setopt_ptr(curl_sys::CURLMOPT_SOCKETFUNCTION, + cb as usize as *const c_char)); + let ptr = &*self.data as *const _; + try!(self.setopt_ptr(curl_sys::CURLMOPT_SOCKETDATA, + ptr as *const c_char)); + return Ok(()); + + // TODO: figure out how to expose `_easy` + extern fn cb(_easy: *mut curl_sys::CURL, + socket: curl_sys::curl_socket_t, + what: c_int, + userptr: *mut c_void, + socketp: *mut c_void) -> c_int { + panic::catch(|| unsafe { + let f = &mut (*(userptr as *mut MultiData)).socket; + f(socket, SocketEvents { bits: what }, socketp as usize) + }); + 0 + } + } + + /// Set data to associate with an internal socket + /// + /// This function creates an association in the multi handle between the + /// given socket and a private token of the application. This is designed + /// for `action` uses. + /// + /// When set, the token will be passed to all future socket callbacks for + /// the specified socket. + /// + /// If the given socket isn't already in use by libcurl, this function will + /// return an error. + /// + /// libcurl only keeps one single token associated with a socket, so + /// calling this function several times for the same socket will make the + /// last set token get used. + /// + /// The idea here being that this association (socket to token) is something + /// that just about every application that uses this API will need and then + /// libcurl can just as well do it since it already has an internal hash + /// table lookup for this. + /// + /// # Typical Usage + /// + /// In a typical application you allocate a struct or at least use some kind + /// of semi-dynamic data for each socket that we must wait for action on + /// when using the `action` approach. + /// + /// When our socket-callback gets called by libcurl and we get to know about + /// yet another socket to wait for, we can use `assign` to point out the + /// particular data so that when we get updates about this same socket + /// again, we don't have to find the struct associated with this socket by + /// ourselves. + pub fn assign(&self, + socket: Socket, + token: usize) -> Result<(), MultiError> { + unsafe { + try!(cvt(curl_sys::curl_multi_assign(self.raw, socket, + token as *mut _))); + Ok(()) + } + } + + /// Set callback to receive timeout values + /// + /// Certain features, such as timeouts and retries, require you to call + /// libcurl even when there is no activity on the file descriptors. + /// + /// Your callback function should install a non-repeating timer with the + /// interval specified. Each time that timer fires, call either `action` or + /// `perform`, depending on which interface you use. + /// + /// A timeout value of `None` means you should delete your timer. + /// + /// A timeout value of 0 means you should call `action` or `perform` (once) + /// as soon as possible. + /// + /// This callback will only be called when the timeout changes. + /// + /// The timer callback should return `true` on success, and `false` on + /// error. This callback can be used instead of, or in addition to, + /// `get_timeout`. + pub fn timer_function(&mut self, f: F) -> Result<(), MultiError> + where F: FnMut(Option) -> bool + Send + 'static, + { + self._timer_function(Box::new(f)) + } + + fn _timer_function(&mut self, + f: Box) -> bool + Send>) + -> Result<(), MultiError> + { + self.data.timer = f; + let cb: curl_sys::curl_multi_timer_callback = cb; + try!(self.setopt_ptr(curl_sys::CURLMOPT_TIMERFUNCTION, + cb as usize as *const c_char)); + let ptr = &*self.data as *const _; + try!(self.setopt_ptr(curl_sys::CURLMOPT_TIMERDATA, + ptr as *const c_char)); + return Ok(()); + + // TODO: figure out how to expose `_multi` + extern fn cb(_multi: *mut curl_sys::CURLM, + timeout_ms: c_long, + user: *mut c_void) -> c_int { + let keep_going = panic::catch(|| unsafe { + let f = &mut (*(user as *mut MultiData)).timer; + if timeout_ms == -1 { + f(None) + } else { + f(Some(Duration::from_millis(timeout_ms as u64))) + } + }).unwrap_or(false); + if keep_going {0} else {-1} + } + } + + fn setopt_ptr(&mut self, + opt: curl_sys::CURLMoption, + val: *const c_char) -> Result<(), MultiError> { + unsafe { + cvt(curl_sys::curl_multi_setopt(self.raw, opt, val)) + } + } + + /// Add an easy handle to a multi session + /// + /// Adds a standard easy handle to the multi stack. This function call will + /// make this multi handle control the specified easy handle. + /// + /// When an easy interface is added to a multi handle, it will use a shared + /// connection cache owned by the multi handle. Removing and adding new easy + /// handles will not affect the pool of connections or the ability to do + /// connection re-use. + /// + /// If you have `timer_function` set in the multi handle (and you really + /// should if you're working event-based with `action` and friends), that + /// callback will be called from within this function to ask for an updated + /// timer so that your main event loop will get the activity on this handle + /// to get started. + /// + /// The easy handle will remain added to the multi handle until you remove + /// it again with `remove` on the returned handle - even when a transfer + /// with that specific easy handle is completed. + pub fn add(&self, mut easy: Easy) -> Result { + // Clear any configuration set by previous transfers because we're + // moving this into a `Send+'static` situation now basically. + easy.transfer(); + + unsafe { + try!(cvt(curl_sys::curl_multi_add_handle(self.raw, easy.raw()))); + } + Ok(EasyHandle { + easy: easy, + _marker: marker::PhantomData, + }) + } + + /// Same as `add`, but works with the `Easy2` type. + pub fn add2(&self, easy: Easy2) -> Result, MultiError> { + unsafe { + try!(cvt(curl_sys::curl_multi_add_handle(self.raw, easy.raw()))); + } + Ok(Easy2Handle { + easy: easy, + _marker: marker::PhantomData, + }) + } + + /// Remove an easy handle from this multi session + /// + /// Removes the easy handle from this multi handle. This will make the + /// returned easy handle be removed from this multi handle's control. + /// + /// When the easy handle has been removed from a multi stack, it is again + /// perfectly legal to invoke `perform` on it. + /// + /// Removing an easy handle while being used is perfectly legal and will + /// effectively halt the transfer in progress involving that easy handle. + /// All other easy handles and transfers will remain unaffected. + pub fn remove(&self, easy: EasyHandle) -> Result { + unsafe { + try!(cvt(curl_sys::curl_multi_remove_handle(self.raw, + easy.easy.raw()))); + } + Ok(easy.easy) + } + + /// Same as `remove`, but for `Easy2Handle`. + pub fn remove2(&self, easy: Easy2Handle) -> Result, MultiError> { + unsafe { + try!(cvt(curl_sys::curl_multi_remove_handle(self.raw, + easy.easy.raw()))); + } + Ok(easy.easy) + } + + /// Read multi stack informationals + /// + /// Ask the multi handle if there are any messages/informationals from the + /// individual transfers. Messages may include informationals such as an + /// error code from the transfer or just the fact that a transfer is + /// completed. More details on these should be written down as well. + pub fn messages(&self, mut f: F) where F: FnMut(Message) { + self._messages(&mut f) + } + + fn _messages(&self, f: &mut FnMut(Message)) { + let mut queue = 0; + unsafe { + loop { + let ptr = curl_sys::curl_multi_info_read(self.raw, &mut queue); + if ptr.is_null() { + break + } + f(Message { ptr: ptr, _multi: self }) + } + } + } + + /// Inform of reads/writes available data given an action + /// + /// When the application has detected action on a socket handled by libcurl, + /// it should call this function with the sockfd argument set to + /// the socket with the action. When the events on a socket are known, they + /// can be passed `events`. When the events on a socket are unknown, pass + /// `Events::new()` instead, and libcurl will test the descriptor + /// internally. + /// + /// The returned integer will contain the number of running easy handles + /// within the multi handle. When this number reaches zero, all transfers + /// are complete/done. When you call `action` on a specific socket and the + /// counter decreases by one, it DOES NOT necessarily mean that this exact + /// socket/transfer is the one that completed. Use `messages` to figure out + /// which easy handle that completed. + /// + /// The `action` function informs the application about updates in the + /// socket (file descriptor) status by doing none, one, or multiple calls to + /// the socket callback function set with the `socket_function` method. They + /// update the status with changes since the previous time the callback was + /// called. + pub fn action(&self, socket: Socket, events: &Events) + -> Result { + let mut remaining = 0; + unsafe { + try!(cvt(curl_sys::curl_multi_socket_action(self.raw, + socket, + events.bits, + &mut remaining))); + Ok(remaining as u32) + } + } + + /// Inform libcurl that a timeout has expired and sockets should be tested. + /// + /// The returned integer will contain the number of running easy handles + /// within the multi handle. When this number reaches zero, all transfers + /// are complete/done. When you call `action` on a specific socket and the + /// counter decreases by one, it DOES NOT necessarily mean that this exact + /// socket/transfer is the one that completed. Use `messages` to figure out + /// which easy handle that completed. + /// + /// Get the timeout time by calling the `timer_function` method. Your + /// application will then get called with information on how long to wait + /// for socket actions at most before doing the timeout action: call the + /// `timeout` method. You can also use the `get_timeout` function to + /// poll the value at any given time, but for an event-based system using + /// the callback is far better than relying on polling the timeout value. + pub fn timeout(&self) -> Result { + let mut remaining = 0; + unsafe { + try!(cvt(curl_sys::curl_multi_socket_action(self.raw, + curl_sys::CURL_SOCKET_BAD, + 0, + &mut remaining))); + Ok(remaining as u32) + } + } + + /// Get how long to wait for action before proceeding + /// + /// An application using the libcurl multi interface should call + /// `get_timeout` to figure out how long it should wait for socket actions - + /// at most - before proceeding. + /// + /// Proceeding means either doing the socket-style timeout action: call the + /// `timeout` function, or call `perform` if you're using the simpler and + /// older multi interface approach. + /// + /// The timeout value returned is the duration at this very moment. If 0, it + /// means you should proceed immediately without waiting for anything. If it + /// returns `None`, there's no timeout at all set. + /// + /// Note: if libcurl returns a `None` timeout here, it just means that + /// libcurl currently has no stored timeout value. You must not wait too + /// long (more than a few seconds perhaps) before you call `perform` again. + pub fn get_timeout(&self) -> Result, MultiError> { + let mut ms = 0; + unsafe { + try!(cvt(curl_sys::curl_multi_timeout(self.raw, &mut ms))); + if ms == -1 { + Ok(None) + } else { + Ok(Some(Duration::from_millis(ms as u64))) + } + } + } + + /// Block until activity is detected or a timeout passes. + /// + /// The timeout is used in millisecond-precision. Large durations are + /// clamped at the maximum value curl accepts. + /// + /// The returned integer will contain the number of internal file + /// descriptors on which interesting events occured. + /// + /// This function is a simpler alternative to using `fdset()` and `select()` + /// and does not suffer from file descriptor limits. + /// + /// # Example + /// + /// ``` + /// use curl::multi::Multi; + /// use std::time::Duration; + /// + /// let m = Multi::new(); + /// + /// // Add some Easy handles... + /// + /// while m.perform().unwrap() > 0 { + /// m.wait(&mut [], Duration::from_secs(1)).unwrap(); + /// } + /// ``` + pub fn wait(&self, waitfds: &mut [WaitFd], timeout: Duration) + -> Result { + let timeout_ms = { + let secs = timeout.as_secs(); + if secs > (i32::max_value() / 1000) as u64 { + // Duration too large, clamp at maximum value. + i32::max_value() + } else { + secs as i32 * 1000 + timeout.subsec_nanos() as i32 / 1000_000 + } + }; + unsafe { + let mut ret = 0; + try!(cvt(curl_sys::curl_multi_wait(self.raw, + waitfds.as_mut_ptr() as *mut _, + waitfds.len() as u32, + timeout_ms, + &mut ret))); + Ok(ret as u32) + } + } + + /// Reads/writes available data from each easy handle. + /// + /// This function handles transfers on all the added handles that need + /// attention in an non-blocking fashion. + /// + /// When an application has found out there's data available for this handle + /// or a timeout has elapsed, the application should call this function to + /// read/write whatever there is to read or write right now etc. This + /// method returns as soon as the reads/writes are done. This function does + /// not require that there actually is any data available for reading or + /// that data can be written, it can be called just in case. It will return + /// the number of handles that still transfer data. + /// + /// If the amount of running handles is changed from the previous call (or + /// is less than the amount of easy handles you've added to the multi + /// handle), you know that there is one or more transfers less "running". + /// You can then call `info` to get information about each individual + /// completed transfer, and that returned info includes `Error` and more. + /// If an added handle fails very quickly, it may never be counted as a + /// running handle. + /// + /// When running_handles is set to zero (0) on the return of this function, + /// there is no longer any transfers in progress. + /// + /// # Return + /// + /// Before libcurl version 7.20.0: If you receive `is_call_perform`, this + /// basically means that you should call `perform` again, before you select + /// on more actions. You don't have to do it immediately, but the return + /// code means that libcurl may have more data available to return or that + /// there may be more data to send off before it is "satisfied". Do note + /// that `perform` will return `is_call_perform` only when it wants to be + /// called again immediately. When things are fine and there is nothing + /// immediate it wants done, it'll return `Ok` and you need to wait for + /// "action" and then call this function again. + /// + /// This function only returns errors etc regarding the whole multi stack. + /// Problems still might have occurred on individual transfers even when + /// this function returns `Ok`. Use `info` to figure out how individual + /// transfers did. + pub fn perform(&self) -> Result { + unsafe { + let mut ret = 0; + try!(cvt(curl_sys::curl_multi_perform(self.raw, &mut ret))); + Ok(ret as u32) + } + } + + /// Extracts file descriptor information from a multi handle + /// + /// This function extracts file descriptor information from a given + /// handle, and libcurl returns its `fd_set` sets. The application can use + /// these to `select()` on, but be sure to `FD_ZERO` them before calling + /// this function as curl_multi_fdset only adds its own descriptors, it + /// doesn't zero or otherwise remove any others. The curl_multi_perform + /// function should be called as soon as one of them is ready to be read + /// from or written to. + /// + /// If no file descriptors are set by libcurl, this function will return + /// `Ok(None)`. Otherwise `Ok(Some(n))` will be returned where `n` the + /// highest descriptor number libcurl set. When `Ok(None)` is returned it + /// is because libcurl currently does something that isn't possible for + /// your application to monitor with a socket and unfortunately you can + /// then not know exactly when the current action is completed using + /// `select()`. You then need to wait a while before you proceed and call + /// `perform` anyway. + /// + /// When doing `select()`, you should use `get_timeout` to figure out + /// how long to wait for action. Call `perform` even if no activity has + /// been seen on the `fd_set`s after the timeout expires as otherwise + /// internal retries and timeouts may not work as you'd think and want. + /// + /// If one of the sockets used by libcurl happens to be larger than what + /// can be set in an `fd_set`, which on POSIX systems means that the file + /// descriptor is larger than `FD_SETSIZE`, then libcurl will try to not + /// set it. Setting a too large file descriptor in an `fd_set` implies an out + /// of bounds write which can cause crashes, or worse. The effect of NOT + /// storing it will possibly save you from the crash, but will make your + /// program NOT wait for sockets it should wait for... + pub fn fdset2(&self, + read: Option<&mut curl_sys::fd_set>, + write: Option<&mut curl_sys::fd_set>, + except: Option<&mut curl_sys::fd_set>) -> Result, MultiError> { + unsafe { + let mut ret = 0; + let read = read.map(|r| r as *mut _).unwrap_or(0 as *mut _); + let write = write.map(|r| r as *mut _).unwrap_or(0 as *mut _); + let except = except.map(|r| r as *mut _).unwrap_or(0 as *mut _); + try!(cvt(curl_sys::curl_multi_fdset(self.raw, + read, + write, + except, + &mut ret))); + if ret == -1 { + Ok(None) + } else { + Ok(Some(ret)) + } + } + } + + #[doc(hidden)] + #[deprecated(note = "renamed to fdset2")] + pub fn fdset(&self, + read: Option<&mut fd_set>, + write: Option<&mut fd_set>, + except: Option<&mut fd_set>) -> Result, MultiError> { + unsafe { + let mut ret = 0; + let read = read.map(|r| r as *mut _).unwrap_or(0 as *mut _); + let write = write.map(|r| r as *mut _).unwrap_or(0 as *mut _); + let except = except.map(|r| r as *mut _).unwrap_or(0 as *mut _); + try!(cvt(curl_sys::curl_multi_fdset(self.raw, + read as *mut _, + write as *mut _, + except as *mut _, + &mut ret))); + if ret == -1 { + Ok(None) + } else { + Ok(Some(ret)) + } + } + } + + /// Attempt to close the multi handle and clean up all associated resources. + /// + /// Cleans up and removes a whole multi stack. It does not free or touch any + /// individual easy handles in any way - they still need to be closed + /// individually. + pub fn close(&self) -> Result<(), MultiError> { + unsafe { + cvt(curl_sys::curl_multi_cleanup(self.raw)) + } + } +} + +fn cvt(code: curl_sys::CURLMcode) -> Result<(), MultiError> { + if code == curl_sys::CURLM_OK { + Ok(()) + } else { + Err(MultiError::new(code)) + } +} + +impl fmt::Debug for Multi { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Multi") + .field("raw", &self.raw) + .finish() + } +} + +impl Drop for Multi { + fn drop(&mut self) { + let _ = self.close(); + } +} + +impl EasyHandle { + /// Sets an internal private token for this `EasyHandle`. + /// + /// This function will set the `CURLOPT_PRIVATE` field on the underlying + /// easy handle. + pub fn set_token(&mut self, token: usize) -> Result<(), Error> { + unsafe { + ::cvt(curl_sys::curl_easy_setopt(self.easy.raw(), + curl_sys::CURLOPT_PRIVATE, + token)) + } + } +} + +impl fmt::Debug for EasyHandle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.easy.fmt(f) + } +} + +impl Easy2Handle { + /// Acquires a reference to the underlying handler for events. + pub fn get_ref(&self) -> &H { + self.easy.get_ref() + } + + /// Acquires a reference to the underlying handler for events. + pub fn get_mut(&mut self) -> &mut H { + self.easy.get_mut() + } + + /// Same as `EasyHandle::set_token` + pub fn set_token(&mut self, token: usize) -> Result<(), Error> { + unsafe { + ::cvt(curl_sys::curl_easy_setopt(self.easy.raw(), + curl_sys::CURLOPT_PRIVATE, + token)) + } + } +} + +impl fmt::Debug for Easy2Handle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.easy.fmt(f) + } +} + +impl<'multi> Message<'multi> { + /// If this message indicates that a transfer has finished, returns the + /// result of the transfer in `Some`. + /// + /// If the message doesn't indicate that a transfer has finished, then + /// `None` is returned. + pub fn result(&self) -> Option> { + unsafe { + if (*self.ptr).msg == curl_sys::CURLMSG_DONE { + Some(::cvt((*self.ptr).data as curl_sys::CURLcode)) + } else { + None + } + } + } + + /// Returns whether this easy message was for the specified easy handle or + /// not. + pub fn is_for(&self, handle: &EasyHandle) -> bool { + unsafe { (*self.ptr).easy_handle == handle.easy.raw() } + } + + /// Same as `is_for`, but for `Easy2Handle`. + pub fn is_for2(&self, handle: &Easy2Handle) -> bool { + unsafe { (*self.ptr).easy_handle == handle.easy.raw() } + } + + /// Returns the token associated with the easy handle that this message + /// represents a completion for. + /// + /// This function will return the token assigned with + /// `EasyHandle::set_token`. This reads the `CURLINFO_PRIVATE` field of the + /// underlying `*mut CURL`. + pub fn token(&self) -> Result { + unsafe { + let mut p = 0usize; + try!(::cvt(curl_sys::curl_easy_getinfo((*self.ptr).easy_handle, + curl_sys::CURLINFO_PRIVATE, + &mut p))); + Ok(p) + } + } +} + +impl<'a> fmt::Debug for Message<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Message") + .field("ptr", &self.ptr) + .finish() + } +} + +impl Events { + /// Creates a new blank event bit mask. + pub fn new() -> Events { + Events { bits: 0 } + } + + /// Set or unset the whether these events indicate that input is ready. + pub fn input(&mut self, val: bool) -> &mut Events { + self.flag(curl_sys::CURL_CSELECT_IN, val) + } + + /// Set or unset the whether these events indicate that output is ready. + pub fn output(&mut self, val: bool) -> &mut Events { + self.flag(curl_sys::CURL_CSELECT_OUT, val) + } + + /// Set or unset the whether these events indicate that an error has + /// happened. + pub fn error(&mut self, val: bool) -> &mut Events { + self.flag(curl_sys::CURL_CSELECT_ERR, val) + } + + fn flag(&mut self, flag: c_int, val: bool) -> &mut Events { + if val { + self.bits |= flag; + } else { + self.bits &= !flag; + } + self + } +} + +impl fmt::Debug for Events { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Events") + .field("input", &(self.bits & curl_sys::CURL_CSELECT_IN != 0)) + .field("output", &(self.bits & curl_sys::CURL_CSELECT_IN != 0)) + .field("error", &(self.bits & curl_sys::CURL_CSELECT_IN != 0)) + .finish() + } +} + +impl SocketEvents { + /// Wait for incoming data. For the socket to become readable. + pub fn input(&self) -> bool { + self.bits & curl_sys::CURL_POLL_IN == curl_sys::CURL_POLL_IN + } + + /// Wait for outgoing data. For the socket to become writable. + pub fn output(&self) -> bool { + self.bits & curl_sys::CURL_POLL_OUT == curl_sys::CURL_POLL_OUT + } + + /// Wait for incoming and outgoing data. For the socket to become readable + /// or writable. + pub fn input_and_output(&self) -> bool { + self.bits & curl_sys::CURL_POLL_INOUT == curl_sys::CURL_POLL_INOUT + } + + /// The specified socket/file descriptor is no longer used by libcurl. + pub fn remove(&self) -> bool { + self.bits & curl_sys::CURL_POLL_REMOVE == curl_sys::CURL_POLL_REMOVE + } +} + +impl fmt::Debug for SocketEvents { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Events") + .field("input", &self.input()) + .field("output", &self.output()) + .field("remove", &self.remove()) + .finish() + } +} + +impl WaitFd { + /// Constructs an empty (invalid) WaitFd. + pub fn new() -> WaitFd { + WaitFd { + inner: curl_sys::curl_waitfd { + fd: 0, + events: 0, + revents: 0, + } + } + } + + /// Set the file descriptor to wait for. + pub fn set_fd(&mut self, fd: Socket) { + self.inner.fd = fd; + } + + /// Indicate that the socket should poll on read events such as new data + /// received. + /// + /// Corresponds to `CURL_WAIT_POLLIN`. + pub fn poll_on_read(&mut self, val: bool) -> &mut WaitFd { + self.flag(curl_sys::CURL_WAIT_POLLIN, val) + } + + /// Indicate that the socket should poll on high priority read events such + /// as out of band data. + /// + /// Corresponds to `CURL_WAIT_POLLPRI`. + pub fn poll_on_priority_read(&mut self, val: bool) -> &mut WaitFd { + self.flag(curl_sys::CURL_WAIT_POLLPRI, val) + } + + /// Indicate that the socket should poll on write events such as the socket + /// being clear to write without blocking. + /// + /// Corresponds to `CURL_WAIT_POLLOUT`. + pub fn poll_on_write(&mut self, val: bool) -> &mut WaitFd { + self.flag(curl_sys::CURL_WAIT_POLLOUT, val) + } + + fn flag(&mut self, flag: c_short, val: bool) -> &mut WaitFd { + if val { + self.inner.events |= flag; + } else { + self.inner.events &= !flag; + } + self + } + + /// After a call to `wait`, returns `true` if `poll_on_read` was set and a + /// read event occured. + pub fn received_read(&self) -> bool { + self.inner.revents & curl_sys::CURL_WAIT_POLLIN == curl_sys::CURL_WAIT_POLLIN + } + + /// After a call to `wait`, returns `true` if `poll_on_priority_read` was set and a + /// priority read event occured. + pub fn received_priority_read(&self) -> bool { + self.inner.revents & curl_sys::CURL_WAIT_POLLPRI == curl_sys::CURL_WAIT_POLLPRI + } + + /// After a call to `wait`, returns `true` if `poll_on_write` was set and a + /// write event occured. + pub fn received_write(&self) -> bool { + self.inner.revents & curl_sys::CURL_WAIT_POLLOUT == curl_sys::CURL_WAIT_POLLOUT + } +} + +#[cfg(unix)] +impl From for WaitFd { + fn from(pfd: pollfd) -> WaitFd { + let mut events = 0; + if pfd.events & POLLIN == POLLIN { + events |= curl_sys::CURL_WAIT_POLLIN; + } + if pfd.events & POLLPRI == POLLPRI { + events |= curl_sys::CURL_WAIT_POLLPRI; + } + if pfd.events & POLLOUT == POLLOUT { + events |= curl_sys::CURL_WAIT_POLLOUT; + } + WaitFd { + inner: curl_sys::curl_waitfd { + fd: pfd.fd, + events: events, + revents: 0, + } + } + } +} + +impl fmt::Debug for WaitFd { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("WaitFd") + .field("fd", &self.inner.fd) + .field("events", &self.inner.fd) + .field("revents", &self.inner.fd) + .finish() + } +} diff --git a/curl-0.4.11/src/panic.rs b/curl-0.4.11/src/panic.rs new file mode 100644 index 000000000..1da217985 --- /dev/null +++ b/curl-0.4.11/src/panic.rs @@ -0,0 +1,30 @@ +use std::any::Any; +use std::cell::RefCell; +use std::panic::{self, AssertUnwindSafe}; + +thread_local!(static LAST_ERROR: RefCell>> = { + RefCell::new(None) +}); + +pub fn catch T>(f: F) -> Option { + if LAST_ERROR.with(|slot| slot.borrow().is_some()) { + return None + } + + // Note that `AssertUnwindSafe` is used here as we prevent reentering + // arbitrary code due to the `LAST_ERROR` check above plus propagation of a + // panic after we return back to user code from C. + match panic::catch_unwind(AssertUnwindSafe(f)) { + Ok(ret) => Some(ret), + Err(e) => { + LAST_ERROR.with(|slot| *slot.borrow_mut() = Some(e)); + None + } + } +} + +pub fn propagate() { + if let Some(t) = LAST_ERROR.with(|slot| slot.borrow_mut().take()) { + panic::resume_unwind(t) + } +} diff --git a/curl-0.4.11/src/version.rs b/curl-0.4.11/src/version.rs new file mode 100644 index 000000000..aaa734f6a --- /dev/null +++ b/curl-0.4.11/src/version.rs @@ -0,0 +1,303 @@ +use std::ffi::CStr; +use std::fmt; +use std::str; + +use curl_sys; +use libc::{c_int, c_char}; + +/// Version information about libcurl and the capabilities that it supports. +pub struct Version { + inner: *mut curl_sys::curl_version_info_data, +} + +unsafe impl Send for Version {} +unsafe impl Sync for Version {} + +/// An iterator over the list of protocols a version supports. +#[derive(Clone)] +pub struct Protocols<'a> { + cur: *const *const c_char, + _inner: &'a Version, +} + +impl Version { + /// Returns the libcurl version that this library is currently linked against. + pub fn num() -> &'static str { + unsafe { + let s = CStr::from_ptr(curl_sys::curl_version() as *const _); + str::from_utf8(s.to_bytes()).unwrap() + } + } + + /// Returns the libcurl version that this library is currently linked against. + pub fn get() -> Version { + unsafe { + let ptr = curl_sys::curl_version_info(curl_sys::CURLVERSION_FOURTH); + assert!(!ptr.is_null()); + Version { inner: ptr } + } + } + + /// Returns the human readable version string, + pub fn version(&self) -> &str { + unsafe { + ::opt_str((*self.inner).version).unwrap() + } + } + + /// Returns a numeric representation of the version number + /// + /// This is a 24 bit number made up of the major number, minor, and then + /// patch number. For example 7.9.8 will return 0x070908. + pub fn version_num(&self) -> u32 { + unsafe { + (*self.inner).version_num as u32 + } + } + + /// Returns a human readable string of the host libcurl is built for. + /// + /// This is discovered as part of the build environment. + pub fn host(&self) -> &str { + unsafe { + ::opt_str((*self.inner).host).unwrap() + } + } + + /// Returns whether libcurl supports IPv6 + pub fn feature_ipv6(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_IPV6) + } + + /// Returns whether libcurl supports SSL + pub fn feature_ssl(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_SSL) + } + + /// Returns whether libcurl supports HTTP deflate via libz + pub fn feature_libz(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_LIBZ) + } + + /// Returns whether libcurl supports HTTP NTLM + pub fn feature_ntlm(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_NTLM) + } + + /// Returns whether libcurl supports HTTP GSSNEGOTIATE + pub fn feature_gss_negotiate(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_GSSNEGOTIATE) + } + + /// Returns whether libcurl was built with debug capabilities + pub fn feature_debug(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_DEBUG) + } + + /// Returns whether libcurl was built with SPNEGO authentication + pub fn feature_spnego(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_SPNEGO) + } + + /// Returns whether libcurl was built with large file support + pub fn feature_largefile(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_LARGEFILE) + } + + /// Returns whether libcurl was built with support for IDNA, domain names + /// with international letters. + pub fn feature_idn(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_IDN) + } + + /// Returns whether libcurl was built with support for SSPI. + pub fn feature_sspi(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_SSPI) + } + + /// Returns whether libcurl was built with asynchronous name lookups. + pub fn feature_async_dns(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_ASYNCHDNS) + } + + /// Returns whether libcurl was built with support for character + /// conversions. + pub fn feature_conv(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_CONV) + } + + /// Returns whether libcurl was built with support for TLS-SRP. + pub fn feature_tlsauth_srp(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_TLSAUTH_SRP) + } + + /// Returns whether libcurl was built with support for NTLM delegation to + /// winbind helper. + pub fn feature_ntlm_wb(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_NTLM_WB) + } + + /// Returns whether libcurl was built with support for unix domain socket + pub fn feature_unix_domain_socket(&self) -> bool { + self.flag(curl_sys::CURL_VERSION_UNIX_SOCKETS) + } + + // /// Returns whether libcurl was built with support for HTTP2. + // pub fn feature_http2(&self) -> bool { + // self.flag(curl_sys::CURL_VERSION_HTTP2) + // } + fn flag(&self, flag: c_int) -> bool { + unsafe { + (*self.inner).features & flag != 0 + } + } + + /// Returns the version of OpenSSL that is used, or None if there is no SSL + /// support. + pub fn ssl_version(&self) -> Option<&str> { + unsafe { + ::opt_str((*self.inner).ssl_version) + } + } + + /// Returns the version of libz that is used, or None if there is no libz + /// support. + pub fn libz_version(&self) -> Option<&str> { + unsafe { + ::opt_str((*self.inner).libz_version) + } + } + + /// Returns an iterator over the list of protocols that this build of + /// libcurl supports. + pub fn protocols(&self) -> Protocols { + unsafe { + Protocols { _inner: self, cur: (*self.inner).protocols } + } + } + + /// If available, the human readable version of ares that libcurl is linked + /// against. + pub fn ares_version(&self) -> Option<&str> { + unsafe { + if (*self.inner).age >= 1 { + ::opt_str((*self.inner).ares) + } else { + None + } + } + } + + /// If available, the version of ares that libcurl is linked against. + pub fn ares_version_num(&self) -> Option { + unsafe { + if (*self.inner).age >= 1 { + Some((*self.inner).ares_num as u32) + } else { + None + } + } + } + + /// If available, the version of libidn that libcurl is linked against. + pub fn libidn_version(&self) -> Option<&str> { + unsafe { + if (*self.inner).age >= 2 { + ::opt_str((*self.inner).libidn) + } else { + None + } + } + } + + /// If available, the version of iconv libcurl is linked against. + pub fn iconv_version_num(&self) -> Option { + unsafe { + if (*self.inner).age >= 3 { + Some((*self.inner).iconv_ver_num as u32) + } else { + None + } + } + } + + /// If available, the version of iconv libcurl is linked against. + pub fn libssh_version(&self) -> Option<&str> { + unsafe { + if (*self.inner).age >= 3 { + ::opt_str((*self.inner).libssh_version) + } else { + None + } + } + } +} + +impl fmt::Debug for Version { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut f = f.debug_struct("Version"); + f.field("version", &self.version()) + .field("host", &self.host()) + .field("feature_ipv6", &self.feature_ipv6()) + .field("feature_ssl", &self.feature_ssl()) + .field("feature_libz", &self.feature_libz()) + .field("feature_ntlm", &self.feature_ntlm()) + .field("feature_gss_negotiate", &self.feature_gss_negotiate()) + .field("feature_debug", &self.feature_debug()) + .field("feature_spnego", &self.feature_debug()) + .field("feature_largefile", &self.feature_debug()) + .field("feature_idn", &self.feature_debug()) + .field("feature_sspi", &self.feature_debug()) + .field("feature_async_dns", &self.feature_debug()) + .field("feature_conv", &self.feature_debug()) + .field("feature_tlsauth_srp", &self.feature_debug()) + .field("feature_ntlm_wb", &self.feature_debug()) + .field("feature_unix_domain_socket", &self.feature_debug()); + + if let Some(s) = self.ssl_version() { + f.field("ssl_version", &s); + } + if let Some(s) = self.libz_version() { + f.field("libz_version", &s); + } + if let Some(s) = self.ares_version() { + f.field("ares_version", &s); + } + if let Some(s) = self.libidn_version() { + f.field("libidn_version", &s); + } + if let Some(s) = self.iconv_version_num() { + f.field("iconv_version_num", &format!("{:x}", s)); + } + if let Some(s) = self.libssh_version() { + f.field("libssh_version", &s); + } + + f.field("protocols", &self.protocols().collect::>()); + + f.finish() + } +} + +impl<'a> Iterator for Protocols<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + unsafe { + if (*self.cur).is_null() { + return None + } + let ret = ::opt_str(*self.cur).unwrap(); + self.cur = self.cur.offset(1); + Some(ret) + } + } +} + +impl<'a> fmt::Debug for Protocols<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list() + .entries(self.clone()) + .finish() + } +} diff --git a/curl-0.4.11/tests/easy.rs b/curl-0.4.11/tests/easy.rs new file mode 100644 index 000000000..09add3149 --- /dev/null +++ b/curl-0.4.11/tests/easy.rs @@ -0,0 +1,693 @@ +extern crate curl; + +use std::cell::{RefCell, Cell}; +use std::io::Read; +use std::rc::Rc; +use std::str; +use std::time::Duration; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {:?}", stringify!($e), e), + }) +} + +use curl::easy::{Easy, List, WriteError, ReadError, Transfer}; + +use server::Server; +mod server; + +fn handle() -> Easy { + let mut e = Easy::new(); + t!(e.timeout(Duration::new(20, 0))); + return e +} + +fn sink(data: &[u8]) -> Result { + Ok(data.len()) +} + +#[test] +fn get_smoke() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut handle = handle(); + t!(handle.url(&s.url("/"))); + t!(handle.perform()); +} + +#[test] +fn get_path() { + let s = Server::new(); + s.receive("\ +GET /foo HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut handle = handle(); + t!(handle.url(&s.url("/foo"))); + t!(handle.perform()); +} + +#[test] +fn write_callback() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("HTTP/1.1 200 OK\r\n\r\nhello!"); + + let mut all = Vec::::new(); + { + let mut handle = handle(); + t!(handle.url(&s.url("/"))); + let mut handle = handle.transfer(); + t!(handle.write_function(|data| { + all.extend(data); + Ok(data.len()) + })); + t!(handle.perform()); + } + assert_eq!(all, b"hello!"); +} + +#[test] +fn resolve() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: example.com:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut list = List::new(); + t!(list.append(&format!("example.com:{}:127.0.0.1", s.addr().port()))); + let mut handle = handle(); + t!(handle.url(&format!("http://example.com:{}/", s.addr().port()))); + t!(handle.resolve(list)); + t!(handle.perform()); +} + +#[test] +fn progress() { + let s = Server::new(); + s.receive("\ +GET /foo HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("HTTP/1.1 200 OK\r\n\r\nHello!"); + + let mut hits = 0; + let mut dl = 0.0; + { + let mut handle = handle(); + t!(handle.url(&s.url("/foo"))); + t!(handle.progress(true)); + t!(handle.write_function(sink)); + + let mut handle = handle.transfer(); + t!(handle.progress_function(|_, a, _, _| { + hits += 1; + dl = a; + true + })); + t!(handle.perform()); + } + assert!(hits > 0); + assert_eq!(dl, 6.0); +} + +#[test] +fn headers() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +Foo: bar\r\n\ +Bar: baz\r\n\ +\r\n +Hello!"); + + let mut headers = Vec::new(); + { + let mut handle = handle(); + t!(handle.url(&s.url("/"))); + + let mut handle = handle.transfer(); + t!(handle.header_function(|h| { + headers.push(str::from_utf8(h).unwrap().to_string()); + true + })); + t!(handle.write_function(sink)); + t!(handle.perform()); + } + assert_eq!(headers, vec![ + "HTTP/1.1 200 OK\r\n".to_string(), + "Foo: bar\r\n".to_string(), + "Bar: baz\r\n".to_string(), + "\r\n".to_string(), + ]); +} + +#[test] +fn fail_on_error() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 401 Not so good\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.fail_on_error(true)); + assert!(h.perform().is_err()); + + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 401 Not so good\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.fail_on_error(false)); + t!(h.perform()); +} + +#[test] +fn port() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: localhost:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url("http://localhost/")); + t!(h.port(s.addr().port())); + t!(h.perform()); +} + +#[test] +fn proxy() { + let s = Server::new(); + s.receive("\ +GET http://example.com/ HTTP/1.1\r\n\ +Host: example.com\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url("http://example.com/")); + t!(h.proxy(&s.url("/"))); + t!(h.perform()); +} + +#[test] +#[ignore] // fails on newer curl versions? seems benign +fn noproxy() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.proxy(&s.url("/"))); + t!(h.noproxy("127.0.0.1")); + t!(h.perform()); +} + +#[test] +fn misc() { + let mut h = handle(); + t!(h.tcp_nodelay(true)); + // t!(h.tcp_keepalive(true)); + // t!(h.tcp_keepidle(Duration::new(3, 0))); + // t!(h.tcp_keepintvl(Duration::new(3, 0))); + t!(h.buffer_size(10)); + t!(h.dns_cache_timeout(Duration::new(1, 0))); +} + +#[test] +fn userpass() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Authorization: Basic YmFyOg==\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.username("foo")); + t!(h.username("bar")); + t!(h.perform()); +} + +#[test] +fn accept_encoding() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +Accept-Encoding: gzip\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.accept_encoding("gzip")); + t!(h.perform()); +} + +#[test] +fn follow_location() { + let s1 = Server::new(); + let s2 = Server::new(); + s1.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s1.send(&format!("\ +HTTP/1.1 301 Moved Permanently\r\n\ +Location: http://{}/foo\r\n\ +\r\n", s2.addr())); + + s2.receive("\ +GET /foo HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s2.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s1.url("/"))); + t!(h.follow_location(true)); + t!(h.perform()); +} + +#[test] +fn put() { + let s = Server::new(); + s.receive("\ +PUT / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +Content-Length: 5\r\n\ +\r\n\ +data\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut data = "data\n".as_bytes(); + let mut list = List::new(); + t!(list.append("Expect:")); + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.put(true)); + t!(h.in_filesize(5)); + t!(h.upload(true)); + t!(h.http_headers(list)); + let mut h = h.transfer(); + t!(h.read_function(|buf| { + Ok(data.read(buf).unwrap()) + })); + t!(h.perform()); +} + +#[test] +fn post1() { + let s = Server::new(); + s.receive("\ +POST / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +Content-Length: 5\r\n\ +Content-Type: application/x-www-form-urlencoded\r\n\ +\r\n\ +data\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.post(true)); + t!(h.post_fields_copy(b"data\n")); + t!(h.perform()); +} + +#[test] +fn post2() { + let s = Server::new(); + s.receive("\ +POST / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +Content-Length: 5\r\n\ +Content-Type: application/x-www-form-urlencoded\r\n\ +\r\n\ +data\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.post(true)); + t!(h.post_fields_copy(b"data\n")); + t!(h.write_function(sink)); + t!(h.perform()); +} + +#[test] +fn post3() { + let s = Server::new(); + s.receive("\ +POST / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +Content-Length: 5\r\n\ +Content-Type: application/x-www-form-urlencoded\r\n\ +\r\n\ +data\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut data = "data\n".as_bytes(); + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.post(true)); + t!(h.post_field_size(5)); + let mut h = h.transfer(); + t!(h.read_function(|buf| { + Ok(data.read(buf).unwrap()) + })); + t!(h.perform()); +} + +#[test] +fn referer() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +Referer: foo\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.referer("foo")); + t!(h.perform()); +} + +#[test] +fn useragent() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +User-Agent: foo\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.useragent("foo")); + t!(h.perform()); +} + +#[test] +fn custom_headers() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Foo: bar\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut custom = List::new(); + t!(custom.append("Foo: bar")); + t!(custom.append("Accept:")); + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.http_headers(custom)); + t!(h.perform()); +} + +#[test] +fn cookie() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +Cookie: foo\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.cookie("foo")); + t!(h.perform()); +} + +#[test] +fn url_encoding() { + let mut h = handle(); + assert_eq!(h.url_encode(b"foo"), "foo"); + assert_eq!(h.url_encode(b"foo bar"), "foo%20bar"); + assert_eq!(h.url_encode(b"foo bar\xff"), "foo%20bar%FF"); + assert_eq!(h.url_encode(b""), ""); + assert_eq!(h.url_decode("foo"), b"foo"); + assert_eq!(h.url_decode("foo%20bar"), b"foo bar"); + assert_eq!(h.url_decode("foo%2"), b"foo%2"); + assert_eq!(h.url_decode("foo%xx"), b"foo%xx"); + assert_eq!(h.url_decode("foo%ff"), b"foo\xff"); + assert_eq!(h.url_decode(""), b""); +} + +#[test] +fn getters() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.cookie_file("/dev/null")); + t!(h.perform()); + assert_eq!(t!(h.response_code()), 200); + assert_eq!(t!(h.redirect_count()), 0); + assert_eq!(t!(h.redirect_url()), None); + assert_eq!(t!(h.content_type()), None); + + let addr = format!("http://{}/", s.addr()); + assert_eq!(t!(h.effective_url()), Some(&addr[..])); + + // TODO: test this + // let cookies = t!(h.cookies()).iter() + // .map(|s| s.to_vec()) + // .collect::>(); + // assert_eq!(cookies.len(), 1); +} + +#[test] +#[should_panic] +fn panic_in_callback() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.header_function(|_| panic!())); + t!(h.perform()); +} + +#[test] +fn abort_read() { + let s = Server::new(); + s.receive("\ +PUT / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +Content-Length: 2\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.read_function(|_| Err(ReadError::Abort))); + t!(h.put(true)); + t!(h.in_filesize(2)); + let mut list = List::new(); + t!(list.append("Expect:")); + t!(h.http_headers(list)); + let err = h.perform().unwrap_err(); + assert!(err.is_aborted_by_callback()); +} + +#[test] +fn pause_write_then_resume() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n +a\n +b"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.progress(true)); + + struct State<'a, 'b> { + paused: Cell, + unpaused: Cell, + transfer: RefCell>, + } + + let h = Rc::new(State { + paused: Cell::new(false), + unpaused: Cell::new(false), + transfer: RefCell::new(h.transfer()), + }); + + let h2 = h.clone(); + t!(h.transfer.borrow_mut().write_function(move |data| { + if h2.unpaused.get() { + h2.unpaused.set(false); + Ok(data.len()) + } else { + h2.paused.set(true); + Err(WriteError::Pause) + } + })); + let h2 = h.clone(); + t!(h.transfer.borrow_mut().progress_function(move |_, _, _, _| { + if h2.paused.get() { + h2.paused.set(false); + h2.unpaused.set(true); + t!(h2.transfer.borrow().unpause_write()); + } + true + })); + t!(h.transfer.borrow().perform()); +} + +#[test] +fn perform_in_perform_is_bad() { + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n +a\n +b"); + + let mut h = handle(); + t!(h.url(&s.url("/"))); + t!(h.progress(true)); + + let h = Rc::new(RefCell::new(h.transfer())); + + let h2 = h.clone(); + t!(h.borrow_mut().write_function(move |data| { + assert!(h2.borrow().perform().is_err()); + Ok(data.len()) + })); + t!(h.borrow().perform()); +} + +// Stupid test to check if unix_socket is callable +#[test] +fn check_unix_socket() { + let mut h = handle(); + h.unix_socket("/var/something.socks").is_ok(); +} + diff --git a/curl-0.4.11/tests/formdata b/curl-0.4.11/tests/formdata new file mode 100644 index 000000000..ce0136250 --- /dev/null +++ b/curl-0.4.11/tests/formdata @@ -0,0 +1 @@ +hello diff --git a/curl-0.4.11/tests/multi.rs b/curl-0.4.11/tests/multi.rs new file mode 100644 index 000000000..4238b73b4 --- /dev/null +++ b/curl-0.4.11/tests/multi.rs @@ -0,0 +1,252 @@ +#![cfg(unix)] + +extern crate curl; +extern crate mio; + +use std::collections::HashMap; +use std::io::{Read, Cursor}; +use std::time::Duration; + +use curl::easy::{Easy, List}; +use curl::multi::Multi; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {:?}", stringify!($e), e), + }) +} + +use server::Server; +mod server; + +#[test] +fn smoke() { + let m = Multi::new(); + let mut e = Easy::new(); + + let s = Server::new(); + s.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + t!(e.url(&s.url("/"))); + let _e = t!(m.add(e)); + while t!(m.perform()) > 0 { + t!(m.wait(&mut [], Duration::from_secs(1))); + } +} + +#[test] +fn smoke2() { + let m = Multi::new(); + + let s1 = Server::new(); + s1.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s1.send("HTTP/1.1 200 OK\r\n\r\n"); + + let s2 = Server::new(); + s2.receive("\ +GET / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +\r\n"); + s2.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut e1 = Easy::new(); + t!(e1.url(&s1.url("/"))); + let _e1 = t!(m.add(e1)); + let mut e2 = Easy::new(); + t!(e2.url(&s2.url("/"))); + let _e2 = t!(m.add(e2)); + + while t!(m.perform()) > 0 { + t!(m.wait(&mut [], Duration::from_secs(1))); + } + + let mut done = 0; + m.messages(|msg| { + msg.result().unwrap().unwrap(); + done += 1; + }); + assert_eq!(done, 2); +} + +#[test] +fn upload_lots() { + use curl::multi::{Socket, SocketEvents, Events}; + + #[derive(Debug)] + enum Message { + Timeout(Option), + Wait(Socket, SocketEvents, usize), + } + + let mut m = Multi::new(); + let poll = t!(mio::Poll::new()); + let (tx, rx) = mio::channel::channel(); + let tx2 = tx.clone(); + t!(m.socket_function(move |socket, events, token| { + t!(tx2.send(Message::Wait(socket, events, token))); + })); + t!(m.timer_function(move |dur| { + t!(tx.send(Message::Timeout(dur))); + true + })); + + let s = Server::new(); + s.receive(&format!("\ +PUT / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +Content-Length: 131072\r\n\ +\r\n\ +{}\n", vec!["a"; 128 * 1024 - 1].join(""))); + s.send("\ +HTTP/1.1 200 OK\r\n\ +\r\n"); + + let mut data = vec![b'a'; 128 * 1024 - 1]; + data.push(b'\n'); + let mut data = Cursor::new(data); + let mut list = List::new(); + t!(list.append("Expect:")); + let mut h = Easy::new(); + t!(h.url(&s.url("/"))); + t!(h.put(true)); + t!(h.read_function(move |buf| { + Ok(data.read(buf).unwrap()) + })); + t!(h.in_filesize(128 * 1024)); + t!(h.upload(true)); + t!(h.http_headers(list)); + + t!(poll.register(&rx, + mio::Token(0), + mio::Ready::all(), + mio::PollOpt::level())); + + let e = t!(m.add(h)); + + assert!(t!(m.perform()) > 0); + let mut next_token = 1; + let mut token_map = HashMap::new(); + let mut cur_timeout = None; + let mut events = mio::Events::with_capacity(128); + let mut running = true; + + while running { + let n = t!(poll.poll(&mut events, cur_timeout)); + + if n == 0 { + if t!(m.timeout()) == 0 { + running = false; + } + } + + for event in events.iter() { + while event.token() == mio::Token(0) { + match rx.try_recv() { + Ok(Message::Timeout(dur)) => cur_timeout = dur, + Ok(Message::Wait(socket, events, token)) => { + let evented = mio::unix::EventedFd(&socket); + if events.remove() { + token_map.remove(&token).unwrap(); + } else { + let mut e = mio::Ready::none(); + if events.input() { + e = e | mio::Ready::readable(); + } + if events.output() { + e = e | mio::Ready::writable(); + } + if token == 0 { + let token = next_token; + next_token += 1; + t!(m.assign(socket, token)); + token_map.insert(token, socket); + t!(poll.register(&evented, + mio::Token(token), + e, + mio::PollOpt::level())); + } else { + t!(poll.reregister(&evented, + mio::Token(token), + e, + mio::PollOpt::level())); + } + } + } + Err(_) => break, + } + } + + if event.token() == mio::Token(0) { + continue + } + + let token = event.token(); + let socket = token_map[&token.into()]; + let mut e = Events::new(); + if event.kind().is_readable() { + e.input(true); + } + if event.kind().is_writable() { + e.output(true); + } + if event.kind().is_error() { + e.error(true); + } + let remaining = t!(m.action(socket, &e)); + if remaining == 0 { + running = false; + } + } + } + + let mut done = 0; + m.messages(|m| { + m.result().unwrap().unwrap(); + done += 1; + }); + assert_eq!(done, 1); + + let mut e = t!(m.remove(e)); + assert_eq!(t!(e.response_code()), 200); +} + +// Tests passing raw file descriptors to Multi::wait. The test is limited to Linux only as the +// semantics of the underlying poll(2) system call used by curl apparently differ on other +// platforms, making the test fail. +#[cfg(target_os = "linux")] +#[test] +fn waitfds() { + use std::fs::File; + use std::os::unix::io::AsRawFd; + use curl::multi::WaitFd; + + let filenames = ["/dev/null", "/dev/zero", "/dev/urandom"]; + let files: Vec = filenames.iter() + .map(|filename| File::open(filename).unwrap()) + .collect(); + let mut waitfds: Vec = files.iter().map(|f| { + let mut waitfd = WaitFd::new(); + waitfd.set_fd(f.as_raw_fd()); + waitfd.poll_on_read(true); + waitfd + }).collect(); + + let m = Multi::new(); + let events = t!(m.wait(&mut waitfds, Duration::from_secs(1))); + assert_eq!(events, 3); + for waitfd in waitfds { + assert!(waitfd.received_read()); + } +} diff --git a/curl-0.4.11/tests/post.rs b/curl-0.4.11/tests/post.rs new file mode 100644 index 000000000..9a76d5c8f --- /dev/null +++ b/curl-0.4.11/tests/post.rs @@ -0,0 +1,109 @@ +extern crate curl; + +use std::str; +use std::time::Duration; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {:?}", stringify!($e), e), + }) +} + +use curl::easy::{Easy, Form}; + +use server::Server; +mod server; + +fn handle() -> Easy { + let mut e = Easy::new(); + t!(e.timeout(Duration::new(20, 0))); + return e +} + +#[test] +fn custom() { + let s = Server::new(); + s.receive("\ +POST / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +Content-Length: 142\r\n\ +Expect: 100-continue\r\n\ +Content-Type: multipart/form-data; boundary=--[..]\r\n\ +\r\n\ +--[..]\r\n\ +Content-Disposition: form-data; name=\"foo\"\r\n\ +\r\n\ +1234\r\n\ +--[..]\r\n"); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut handle = handle(); + let mut form = Form::new(); + t!(form.part("foo").contents(b"1234").add()); + t!(handle.url(&s.url("/"))); + t!(handle.httppost(form)); + t!(handle.perform()); +} + +#[test] +fn buffer() { + let s = Server::new(); + s.receive("\ +POST / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +Content-Length: 181\r\n\ +Expect: 100-continue\r\n\ +Content-Type: multipart/form-data; boundary=--[..]\r\n\ +\r\n\ +--[..]\r\n\ +Content-Disposition: form-data; name=\"foo\"; filename=\"bar\"\r\n\ +Content-Type: foo/bar\r\n\ +\r\n\ +1234\r\n\ +--[..]\r\n"); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut handle = handle(); + let mut form = Form::new(); + t!(form.part("foo") + .buffer("bar", b"1234".to_vec()) + .content_type("foo/bar") + .add()); + t!(handle.url(&s.url("/"))); + t!(handle.httppost(form)); + t!(handle.perform()); +} + +#[test] +fn file() { + let s = Server::new(); + let formdata = include_str!("formdata"); + s.receive(format!("\ +POST / HTTP/1.1\r\n\ +Host: 127.0.0.1:$PORT\r\n\ +Accept: */*\r\n\ +Content-Length: {}\r\n\ +Expect: 100-continue\r\n\ +Content-Type: multipart/form-data; boundary=--[..]\r\n\ +\r\n\ +--[..]\r\n\ +Content-Disposition: form-data; name=\"foo\"; filename=\"formdata\"\r\n\ +Content-Type: application/octet-stream\r\n\ +\r\n\ +{}\ +\r\n\ +--[..]\r\n", 199 + formdata.len(), formdata).as_str()); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut handle = handle(); + let mut form = Form::new(); + t!(form.part("foo") + .file("tests/formdata") + .add()); + t!(handle.url(&s.url("/"))); + t!(handle.httppost(form)); + t!(handle.perform()); +} diff --git a/curl-0.4.11/tests/server/mod.rs b/curl-0.4.11/tests/server/mod.rs new file mode 100644 index 000000000..445cf901e --- /dev/null +++ b/curl-0.4.11/tests/server/mod.rs @@ -0,0 +1,175 @@ +#![allow(dead_code)] + +use std::collections::HashSet; +use std::net::{TcpListener, SocketAddr, TcpStream}; +use std::io::prelude::*; +use std::thread; +use std::sync::mpsc::{Sender, Receiver, channel}; +use std::io::BufReader; + +pub struct Server { + messages: Option>, + addr: SocketAddr, + thread: Option>, +} + +enum Message { + Read(String), + Write(String), +} + +fn run(listener: &TcpListener, rx: &Receiver) { + let mut socket = BufReader::new(listener.accept().unwrap().0); + for msg in rx.iter() { + match msg { + Message::Read(ref expected) => { + let mut expected = &expected[..]; + let mut expected_headers = HashSet::new(); + while let Some(i) = expected.find("\n") { + let line = &expected[..i + 1]; + expected = &expected[i + 1..]; + expected_headers.insert(line); + if line == "\r\n" { + break + } + } + + let mut expected_len = None; + while expected_headers.len() > 0 { + let mut actual = String::new(); + t!(socket.read_line(&mut actual)); + if actual.starts_with("Content-Length") { + let len = actual.split(": ").skip(1).next().unwrap(); + expected_len = len.trim().parse().ok(); + } + // various versions of libcurl do different things here + if actual == "Proxy-Connection: Keep-Alive\r\n" { + continue + } + if expected_headers.remove(&actual[..]) { + continue + } + + let mut found = None; + for header in expected_headers.iter() { + if lines_match(header, &actual) { + found = Some(header.clone()); + break + } + } + if let Some(found) = found { + expected_headers.remove(&found); + continue + } + panic!("unexpected header: {:?} (remaining headers {:?})", + actual, expected_headers); + } + for header in expected_headers { + panic!("expected header but not found: {:?}", header); + } + + let mut line = String::new(); + let mut socket = match expected_len { + Some(amt) => socket.by_ref().take(amt), + None => socket.by_ref().take(expected.len() as u64), + }; + while socket.limit() > 0 { + line.truncate(0); + t!(socket.read_line(&mut line)); + if line.len() == 0 { + break + } + if expected.len() == 0 { + panic!("unexpected line: {:?}", line); + } + let i = expected.find("\n").unwrap_or(expected.len() - 1); + let expected_line = &expected[..i + 1]; + expected = &expected[i + 1..]; + if lines_match(expected_line, &line) { + continue + } + panic!("lines didn't match:\n\ + expected: {:?}\n\ + actual: {:?}\n", expected_line, line) + } + if expected.len() != 0 { + println!("didn't get expected data: {:?}", expected); + } + } + Message::Write(ref to_write) => { + t!(socket.get_mut().write_all(to_write.as_bytes())); + return + } + } + } + + let mut dst = Vec::new(); + t!(socket.read_to_end(&mut dst)); + assert!(dst.len() == 0); +} + +fn lines_match(expected: &str, mut actual: &str) -> bool { + for (i, part) in expected.split("[..]").enumerate() { + match actual.find(part) { + Some(j) => { + if i == 0 && j != 0 { + return false + } + actual = &actual[j + part.len()..]; + } + None => { + return false + } + } + } + actual.is_empty() || expected.ends_with("[..]") +} + +impl Server { + pub fn new() -> Server { + let listener = t!(TcpListener::bind("127.0.0.1:0")); + let addr = t!(listener.local_addr()); + let (tx, rx) = channel(); + let thread = thread::spawn(move || run(&listener, &rx)); + Server { + messages: Some(tx), + addr: addr, + thread: Some(thread), + } + } + + pub fn receive(&self, msg: &str) { + let msg = msg.replace("$PORT", &self.addr.port().to_string()); + self.msg(Message::Read(msg)); + } + + pub fn send(&self, msg: &str) { + let msg = msg.replace("$PORT", &self.addr.port().to_string()); + self.msg(Message::Write(msg)); + } + + fn msg(&self, msg: Message) { + t!(self.messages.as_ref().unwrap().send(msg)); + } + + pub fn addr(&self) -> &SocketAddr { + &self.addr + } + + pub fn url(&self, path: &str) -> String { + format!("http://{}{}", self.addr, path) + } +} + +impl Drop for Server { + fn drop(&mut self) { + drop(TcpStream::connect(&self.addr)); + drop(self.messages.take()); + let res = self.thread.take().unwrap().join(); + if !thread::panicking() { + t!(res); + } else if let Err(e) = res { + println!("child server thread also failed: {:?}", e); + } + } +} diff --git a/curl-sys-0.4.1/.cargo-checksum.json b/curl-sys-0.4.1/.cargo-checksum.json new file mode 100644 index 000000000..b7c29319d --- /dev/null +++ b/curl-sys-0.4.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"f46e49c7125131f5afaded06944d6888b55cbdf8eba05dae73c954019b907961"} \ No newline at end of file diff --git a/curl-sys-0.4.1/Cargo.toml b/curl-sys-0.4.1/Cargo.toml new file mode 100644 index 000000000..5f1963fc7 --- /dev/null +++ b/curl-sys-0.4.1/Cargo.toml @@ -0,0 +1,49 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "curl-sys" +version = "0.4.1" +authors = ["Carl Lerche ", "Alex Crichton "] +build = "build.rs" +links = "curl" +description = "Native bindings to the libcurl library" +documentation = "https://docs.rs/curl-sys" +categories = ["external-ffi-bindings"] +license = "MIT" +repository = "https://github.com/alexcrichton/curl-rust" + +[lib] +name = "curl_sys" +path = "lib.rs" +[dependencies.libc] +version = "0.2" + +[dependencies.libz-sys] +version = ">= 0" +[build-dependencies.cc] +version = "1.0" + +[build-dependencies.pkg-config] +version = "0.3" +[target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.openssl-sys] +version = "0.9" +[target."cfg(target_env = \"msvc\")".build-dependencies.vcpkg] +version = "0.2" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["winsock2", "ws2def"] +[badges.appveyor] +repository = "alexcrichton/curl-rust" + +[badges.travis-ci] +repository = "alexcrichton/curl-rust" diff --git a/curl-sys-0.4.1/LICENSE b/curl-sys-0.4.1/LICENSE new file mode 100644 index 000000000..5f5e4b09d --- /dev/null +++ b/curl-sys-0.4.1/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 Carl Lerche + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/curl-sys-0.4.1/build.rs b/curl-sys-0.4.1/build.rs new file mode 100644 index 000000000..6b3787c9c --- /dev/null +++ b/curl-sys-0.4.1/build.rs @@ -0,0 +1,420 @@ +extern crate pkg_config; +#[cfg(target_env = "msvc")] +extern crate vcpkg; +extern crate cc; + +use std::ascii::AsciiExt; +use std::env; +use std::ffi::OsString; +use std::fs; +use std::path::{PathBuf, Path, Component, Prefix}; +use std::process::Command; +use std::io::ErrorKind; + +macro_rules! t { + ($e:expr) => (match $e { + Ok(t) => t, + Err(e) => panic!("{} return the error {}", stringify!($e), e), + }) +} + +fn main() { + let target = env::var("TARGET").unwrap(); + let host = env::var("HOST").unwrap(); + let src = env::current_dir().unwrap(); + let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let windows = target.contains("windows"); + + // OSX and Haiku ships libcurl by default, so we just use that version + // unconditionally. + if target.contains("apple") || target.contains("haiku") { + return println!("cargo:rustc-flags=-l curl"); + } + + // Illumos/Solaris requires explicit linking with libnsl + if target.contains("solaris") { + println!("cargo:rustc-flags=-l nsl"); + } + + // Next, fall back and try to use pkg-config if its available. + if !target.contains("windows") { + match pkg_config::find_library("libcurl") { + Ok(lib) => { + for path in lib.include_paths.iter() { + println!("cargo:include={}", path.display()); + } + return + } + Err(e) => println!("Couldn't find libcurl from \ + pkgconfig ({:?}), compiling it from source...", e), + } + } + + if try_vcpkg() { + return; + } + + if !Path::new("curl/.git").exists() { + let _ = Command::new("git").args(&["submodule", "update", "--init"]) + .status(); + } + + println!("cargo:rustc-link-search=native={}/lib", dst.display()); + println!("cargo:rustc-link-lib=static=curl"); + println!("cargo:root={}", dst.display()); + println!("cargo:include={}/include", dst.display()); + if windows { + println!("cargo:rustc-link-lib=ws2_32"); + println!("cargo:rustc-link-lib=crypt32"); + } + + // MSVC builds are just totally different + if target.contains("msvc") { + return build_msvc(&target); + } + + let openssl_root = register_dep("OPENSSL"); + let zlib_root = register_dep("Z"); + let nghttp2_root = register_dep("NGHTTP2"); + + let cfg = cc::Build::new(); + let compiler = cfg.get_compiler(); + + let _ = fs::create_dir(&dst.join("build")); + + let mut cmd = Command::new("sh"); + let mut cflags = OsString::new(); + for arg in compiler.args() { + cflags.push(arg); + cflags.push(" "); + } + + // Can't run ./configure directly on msys2 b/c we're handing in + // Windows-style paths (those starting with C:\), but it chokes on those. + // For that reason we build up a shell script with paths converted to + // posix versions hopefully... + // + // Also apparently the buildbots choke unless we manually set LD, who knows + // why?! + cmd.env("CC", compiler.path()) + .env("CFLAGS", cflags) + .env("LD", &which("ld").unwrap()) + .env("VERBOSE", "1") + .current_dir(&dst.join("build")) + .arg(msys_compatible(&src.join("curl/configure"))); + + // For now this build script doesn't support paths with spaces in them. This + // is arguably a but in curl's configure script, but we could also try to + // paper over it by using a tmp directory which *doesn't* have spaces in it. + // As of now though that's not implemented so just give a nicer error for + // the time being. + let wants_space_error = windows && + (dst.to_str().map(|s| s.contains(" ")).unwrap_or(false) || + src.to_str().map(|s| s.contains(" ")).unwrap_or(false)); + if wants_space_error { + panic!("\n\nunfortunately ./configure of libcurl is known to \ + fail if there's a space in the path to the current \ + directory\n\n\ + there's a space in either\n {}\n {}\nand this will cause the \ + build to fail\n\n\ + the MSVC build should work with a directory that has \ + spaces in it, and it would also work to move this to a \ + different directory without spaces\n\n", + src.display(), dst.display()) + } + + if windows { + cmd.arg("--with-winssl"); + } else { + cmd.arg("--without-ca-bundle"); + cmd.arg("--without-ca-path"); + } + if let Some(root) = openssl_root { + cmd.arg(format!("--with-ssl={}", msys_compatible(&root))); + } + if let Some(root) = zlib_root { + cmd.arg(format!("--with-zlib={}", msys_compatible(&root))); + } + cmd.arg("--enable-static=yes"); + cmd.arg("--enable-shared=no"); + match &env::var("PROFILE").unwrap()[..] { + "bench" | "release" => { + cmd.arg("--enable-optimize"); + } + _ => { + cmd.arg("--enable-debug"); + cmd.arg("--disable-optimize"); + } + } + cmd.arg(format!("--prefix={}", msys_compatible(&dst))); + + if target != host && + (!target.contains("windows") || !host.contains("windows")) { + // NOTE GNU terminology + // BUILD = machine where we are (cross) compiling curl + // HOST = machine where the compiled curl will be used + // TARGET = only relevant when compiling compilers + if target.contains("windows") { + // curl's configure can't parse `-windows-` triples when used + // as `--host`s. In those cases we use this combination of + // `host` and `target` that appears to do the right thing. + cmd.arg(format!("--host={}", host)); + cmd.arg(format!("--target={}", target)); + } else { + cmd.arg(format!("--build={}", host)); + cmd.arg(format!("--host={}", target)); + } + } + + if let Some(root) = nghttp2_root { + cmd.arg(format!("--with-nghttp2={}", msys_compatible(&root))); + } else { + cmd.arg("--without-nghttp2"); + } + + cmd.arg("--without-librtmp"); + cmd.arg("--without-libidn2"); + cmd.arg("--without-libssh2"); + cmd.arg("--without-libpsl"); + cmd.arg("--disable-ldap"); + cmd.arg("--disable-ldaps"); + cmd.arg("--disable-ftp"); + cmd.arg("--disable-rtsp"); + cmd.arg("--disable-dict"); + cmd.arg("--disable-telnet"); + cmd.arg("--disable-tftp"); + cmd.arg("--disable-pop3"); + cmd.arg("--disable-imap"); + cmd.arg("--disable-smtp"); + cmd.arg("--disable-gopher"); + cmd.arg("--disable-manual"); + cmd.arg("--disable-smb"); + cmd.arg("--disable-sspi"); + cmd.arg("--disable-manual"); + cmd.arg("--disable-unix-sockets"); + cmd.arg("--disable-versioned-symbols"); + cmd.arg("--enable-hidden-symbols"); + cmd.arg("--disable-libcurl-option"); + + run(&mut cmd, "sh"); + run(make() + .arg(&format!("-j{}", env::var("NUM_JOBS").unwrap())) + .current_dir(&dst.join("build")), "make"); + run(make() + .arg("install") + .current_dir(&dst.join("build")), "make"); +} + +fn run(cmd: &mut Command, program: &str) { + println!("running: {:?}", cmd); + let status = match cmd.status() { + Ok(status) => status, + Err(ref e) if e.kind() == ErrorKind::NotFound => { + fail(&format!("failed to execute command: {}\nis `{}` not installed?", + e, program)); + } + Err(e) => fail(&format!("failed to execute command: {}", e)), + }; + if !status.success() { + fail(&format!("command did not execute successfully, got: {}", status)); + } +} + +fn fail(s: &str) -> ! { + panic!("\n{}\n\nbuild script failed, must exit now", s) +} + +fn make() -> Command { + let cmd = if cfg!(target_os = "freebsd") {"gmake"} else {"make"}; + let mut cmd = Command::new(cmd); + // We're using the MSYS make which doesn't work with the mingw32-make-style + // MAKEFLAGS, so remove that from the env if present. + if cfg!(windows) { + cmd.env_remove("MAKEFLAGS").env_remove("MFLAGS"); + } + return cmd +} + +fn which(cmd: &str) -> Option { + let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX); + let paths = env::var_os("PATH").unwrap(); + env::split_paths(&paths).map(|p| p.join(&cmd)).find(|p| { + fs::metadata(p).is_ok() + }) +} + +fn msys_compatible(path: &Path) -> String { + let mut path_string = path.to_str().unwrap().to_string(); + if !cfg!(windows) { + return path_string; + } + + // Replace e.g. C:\ with /c/ + if let Component::Prefix(prefix_component) = path.components().next().unwrap() { + if let Prefix::Disk(disk) = prefix_component.kind() { + let from = format!("{}:\\", disk as char); + let to = format!("/{}/", (disk as char).to_ascii_lowercase()); + path_string = path_string.replace(&from, &to); + } + } + path_string.replace("\\", "/") +} + +fn register_dep(dep: &str) -> Option { + if let Some(s) = env::var_os(&format!("DEP_{}_ROOT", dep)) { + prepend("PKG_CONFIG_PATH", Path::new(&s).join("lib/pkgconfig")); + return Some(s.into()) + } + if let Some(s) = env::var_os(&format!("DEP_{}_INCLUDE", dep)) { + let root = Path::new(&s).parent().unwrap(); + env::set_var(&format!("DEP_{}_ROOT", dep), root); + let path = root.join("lib/pkgconfig"); + if path.exists() { + prepend("PKG_CONFIG_PATH", path); + return Some(root.to_path_buf()) + } + } + + return None; + + fn prepend(var: &str, val: PathBuf) { + let prefix = env::var(var).unwrap_or(String::new()); + let mut v = vec![val]; + v.extend(env::split_paths(&prefix)); + env::set_var(var, &env::join_paths(v).unwrap()); + } +} + +fn build_msvc(target: &str) { + let cmd = cc::windows_registry::find(target, "nmake.exe"); + let mut cmd = cmd.unwrap_or(Command::new("nmake.exe")); + let src = env::current_dir().unwrap(); + let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let machine = if target.starts_with("x86_64") { + "x64" + } else if target.starts_with("i686") { + "x86" + } else { + panic!("unknown msvc target: {}", target); + }; + + t!(fs::create_dir_all(dst.join("include/curl"))); + t!(fs::create_dir_all(dst.join("lib"))); + + drop(fs::remove_dir_all(&dst.join("build"))); + cp_r(&src.join("curl"), &dst.join("build")); + cmd.current_dir(dst.join("build/winbuild")); + cmd.arg("/f").arg("Makefile.vc") + .arg("MODE=static") + .arg("ENABLE_IDN=yes") + .arg("DEBUG=no") + .arg("GEN_PDB=no") + .arg("ENABLE_WINSSL=yes") + .arg("ENABLE_SSPI=yes") + .arg(format!("MACHINE={}", machine)); + + // These env vars are intended for `make` usually, not nmake, so remove them + // unconditionally + cmd.env_remove("MAKEFLAGS") + .env_remove("MFLAGS"); + + let features = env::var("CARGO_CFG_TARGET_FEATURE") + .unwrap_or(String::new()); + if features.contains("crt-static") { + cmd.arg("RTLIBCFG=static"); + } + + if let Some(inc) = env::var_os("DEP_Z_ROOT") { + let inc = PathBuf::from(inc); + let mut s = OsString::from("WITH_DEVEL="); + s.push(&inc); + cmd.arg("WITH_ZLIB=static").arg(s); + + // the build system for curl expects this library to be called + // zlib_a.lib, so make sure it's named correctly (where libz-sys just + // produces zlib.lib) + let _ = fs::remove_file(&inc.join("lib/zlib_a.lib")); + t!(fs::copy(inc.join("lib/zlib.lib"), inc.join("lib/zlib_a.lib"))); + } + run(&mut cmd, "nmake"); + + let name = format!("libcurl-vc-{}-release-static-zlib-static-\ + ipv6-sspi-winssl", machine); + let libs = dst.join("build/builds").join(name); + + t!(fs::copy(libs.join("lib/libcurl_a.lib"), dst.join("lib/curl.lib"))); + for f in t!(fs::read_dir(libs.join("include/curl"))) { + let path = t!(f).path(); + let dst = dst.join("include/curl").join(path.file_name().unwrap()); + t!(fs::copy(path, dst)); + } + t!(fs::remove_dir_all(dst.join("build/builds"))); + println!("cargo:rustc-link-lib=wldap32"); + println!("cargo:rustc-link-lib=advapi32"); + println!("cargo:rustc-link-lib=normaliz"); +} + +#[cfg(not(target_env = "msvc"))] +fn try_vcpkg() -> bool { + false +} + +#[cfg(target_env = "msvc")] +fn try_vcpkg() -> bool { + + // the import library for the dll is called libcurl_imp + let mut successful_probe_details = + match vcpkg::Config::new().lib_names("libcurl_imp", "libcurl") + .emit_includes(true).probe("curl") { + Ok(details) => Some(details), + Err(e) => { + println!("first run of vcpkg did not find libcurl: {}", e); + None + } + }; + + if successful_probe_details.is_none() { + match vcpkg::Config::new().lib_name("libcurl") + .emit_includes(true).probe("curl") { + Ok(details) => successful_probe_details = Some(details), + Err(e) => println!("second run of vcpkg did not find libcurl: {}", e), + } + } + + if successful_probe_details.is_some() { + // Found libcurl which depends on openssl, libssh2 and zlib + // in the a default vcpkg installation. Probe for them + // but do not fail if they are not present as we may be working + // with a customized vcpkg installation. + vcpkg::Config::new() + .lib_name("libeay32") + .lib_name("ssleay32") + .probe("openssl").ok(); + + vcpkg::probe_package("libssh2").ok(); + + vcpkg::Config::new() + .lib_names("zlib", "zlib1") + .probe("zlib").ok(); + + println!("cargo:rustc-link-lib=crypt32"); + println!("cargo:rustc-link-lib=gdi32"); + println!("cargo:rustc-link-lib=user32"); + println!("cargo:rustc-link-lib=wldap32"); + return true; + } + false +} + +fn cp_r(src: &Path, dst: &Path) { + t!(fs::create_dir(dst)); + for e in t!(src.read_dir()).map(|e| t!(e)) { + let src = e.path(); + let dst = dst.join(e.file_name()); + if t!(e.file_type()).is_dir() { + cp_r(&src, &dst); + } else { + t!(fs::copy(&src, &dst)); + } + } +} diff --git a/curl-sys-0.4.1/lib.rs b/curl-sys-0.4.1/lib.rs new file mode 100644 index 000000000..6414ca60a --- /dev/null +++ b/curl-sys-0.4.1/lib.rs @@ -0,0 +1,1052 @@ +#![allow(bad_style)] +#![doc(html_root_url = "https://docs.rs/curl-sys/0.3")] + +extern crate libc; +#[cfg(not(target_env = "msvc"))] +extern crate libz_sys; +#[cfg(all(unix, not(target_os = "macos")))] +extern crate openssl_sys; +#[cfg(windows)] +extern crate winapi; + +use libc::{c_int, c_char, c_uint, c_short, c_long, c_double, c_void, size_t, time_t}; +use libc::c_ulong; + +#[cfg(unix)] +pub use libc::fd_set; +#[cfg(windows)] +pub use winapi::um::winsock2::fd_set; +#[cfg(windows)] +use winapi::shared::ws2def::SOCKADDR; + +#[cfg(target_env = "msvc")] +#[doc(hidden)] +pub type __enum_ty = libc::c_int; +#[cfg(not(target_env = "msvc"))] +#[doc(hidden)] +pub type __enum_ty = libc::c_uint; + +pub type CURLINFO = __enum_ty; +pub type CURLoption = __enum_ty; +pub type CURLcode = __enum_ty; +pub type CURLversion = __enum_ty; +pub type curl_off_t = i64; + +pub enum CURL {} + +#[cfg(unix)] +pub type curl_socket_t = libc::c_int; +#[cfg(unix)] +pub const CURL_SOCKET_BAD: curl_socket_t = -1; +#[cfg(all(windows, target_pointer_width = "32"))] +pub type curl_socket_t = libc::c_uint; +#[cfg(all(windows, target_pointer_width = "64"))] +pub type curl_socket_t = u64; +#[cfg(windows)] +pub const CURL_SOCKET_BAD: curl_socket_t = !0; + +pub enum curl_httppost { + // Note that this changed in some versions of libcurl, so we currently don't + // bind the fields as they're apparently not stable. + // pub next: *mut curl_httppost, + // pub name: *mut c_char, + // pub namelength: c_long, + // pub contents: *mut c_char, + // pub contentslength: c_long, + // pub buffer: *mut c_char, + // pub bufferlength: c_long, + // pub contenttype: *mut c_char, + // pub contentheader: *mut curl_slist, + // pub more: *mut curl_httppost, + // pub flags: c_long, + // pub showfilename: *mut c_char, + // pub userp: *mut c_void, +} + +// pub const HTTPPOST_FILENAME: c_long = 1 << 0; +// pub const HTTPPOST_READFILE: c_long = 1 << 1; +// pub const HTTPPOST_PTRNAME: c_long = 1 << 2; +// pub const HTTPPOST_PTRCONTENTS: c_long = 1 << 3; +// pub const HTTPPOST_BUFFER: c_long = 1 << 4; +// pub const HTTPPOST_PTRBUFFER: c_long = 1 << 5; +// pub const HTTPPOST_CALLBACK: c_long = 1 << 6; + +pub type curl_progress_callback = extern fn(*mut c_void, + c_double, + c_double, + c_double, + c_double) -> c_int; +// pub type curl_xferinfo_callback = extern fn(*mut c_void, +// curl_off_t, +// curl_off_t, +// curl_off_t, +// curl_off_t) -> c_int; + +pub const CURL_WRITEFUNC_PAUSE: size_t = 0x10000001; + +pub type curl_write_callback = extern fn(*mut c_char, + size_t, + size_t, + *mut c_void) -> size_t; + +pub type curlfiletype = __enum_ty; +pub const CURLFILETYPE_FILE: curlfiletype = 0; +pub const CURLFILETYPE_DIRECTORY: curlfiletype = 1; +pub const CURLFILETYPE_SYMLINK: curlfiletype = 2; +pub const CURLFILETYPE_DEVICE_BLOCK: curlfiletype = 3; +pub const CURLFILETYPE_DEVICE_CHAR: curlfiletype = 4; +pub const CURLFILETYPE_NAMEDPIPE: curlfiletype = 5; +pub const CURLFILETYPE_SOCKET: curlfiletype = 6; +pub const CURLFILETYPE_DOOR: curlfiletype = 7; +pub const CURLFILETYPE_UNKNOWN: curlfiletype = 8; + +pub const CURLFINFOFLAG_KNOWN_FILENAME: c_uint = 1 << 0; +pub const CURLFINFOFLAG_KNOWN_FILETYPE: c_uint = 1 << 1; +pub const CURLFINFOFLAG_KNOWN_TIME: c_uint = 1 << 2; +pub const CURLFINFOFLAG_KNOWN_PERM: c_uint = 1 << 3; +pub const CURLFINFOFLAG_KNOWN_UID: c_uint = 1 << 4; +pub const CURLFINFOFLAG_KNOWN_GID: c_uint = 1 << 5; +pub const CURLFINFOFLAG_KNOWN_SIZE: c_uint = 1 << 6; +pub const CURLFINFOFLAG_KNOWN_HLINKCOUNT: c_uint = 1 << 7; + +#[repr(C)] +pub struct curl_fileinfo { + pub filename: *mut c_char, + pub filetype: curlfiletype, + pub time: time_t, + pub perm: c_uint, + pub uid: c_int, + pub gid: c_int, + pub size: curl_off_t, + pub hardlinks: c_long, + + pub strings_time: *mut c_char, + pub strings_perm: *mut c_char, + pub strings_user: *mut c_char, + pub strings_group: *mut c_char, + pub strings_target: *mut c_char, + + pub flags: c_uint, + pub b_data: *mut c_char, + pub b_size: size_t, + pub b_used: size_t, +} + +pub const CURL_CHUNK_BGN_FUNC_OK: c_long = 0; +pub const CURL_CHUNK_BGN_FUNC_FAIL: c_long = 1; +pub const CURL_CHUNK_BGN_FUNC_SKIP: c_long = 2; +pub type curl_chunk_bgn_callback = extern fn(*const c_void, + *mut c_void, + c_int) -> c_long; + +pub const CURL_CHUNK_END_FUNC_OK: c_long = 0; +pub const CURL_CHUNK_END_FUNC_FAIL: c_long = 1; +pub type curl_chunk_end_callback = extern fn(*mut c_void) -> c_long; + +pub const CURL_FNMATCHFUNC_MATCH: c_int = 0; +pub const CURL_FNMATCHFUNC_NOMATCH: c_int = 1; +pub const CURL_FNMATCHFUNC_FAIL: c_int = 2; +pub type curl_fnmatch_callback = extern fn(*mut c_void, + *const c_char, + *const c_char) -> c_int; + +pub const CURL_SEEKFUNC_OK: c_int = 0; +pub const CURL_SEEKFUNC_FAIL: c_int = 1; +pub const CURL_SEEKFUNC_CANTSEEK: c_int = 2; +pub type curl_seek_callback = extern fn(*mut c_void, + curl_off_t, + c_int) -> c_int; + +pub const CURL_READFUNC_ABORT: size_t = 0x10000000; +pub const CURL_READFUNC_PAUSE: size_t = 0x10000001; +pub type curl_read_callback = extern fn(*mut c_char, + size_t, + size_t, + *mut c_void) -> size_t; + +// pub const CURL_SOCKOPT_OK: c_int = 0; +// pub const CURL_SOCKOPT_ERROR: c_int = 1; +// pub const CURL_SOCKOPT_ALREADY_CONNECTED: c_int = 2; +// pub type curl_sockopt_callback = extern fn(*mut c_void, +// curl_socket_t, +// curlsocktype) -> c_int; + +pub type curlioerr = __enum_ty; +pub const CURLIOE_OK: curlioerr = 0; +pub const CURLIOE_UNKNOWNCMD: curlioerr = 1; +pub const CURLIOE_FAILRESTART: curlioerr = 2; + +pub type curliocmd = __enum_ty; +pub const CURLIOCMD_NOP: curliocmd = 0; +pub const CURLIOCMD_RESTARTREAD: curliocmd = 1; + +pub type curl_ioctl_callback = extern fn(*mut CURL, c_int, *mut c_void) -> curlioerr; + +pub type curl_malloc_callback = extern fn(size_t) -> *mut c_void; +pub type curl_free_callback = extern fn(*mut c_void); +pub type curl_realloc_callback = extern fn(*mut c_void, size_t) -> *mut c_void; +pub type curl_strdup_callback = extern fn(*const c_char) -> *mut c_char; +pub type curl_calloc_callback = extern fn(size_t, size_t) -> *mut c_void; + +pub type curl_infotype = __enum_ty; +pub const CURLINFO_TEXT: curl_infotype = 0; +pub const CURLINFO_HEADER_IN: curl_infotype = 1; +pub const CURLINFO_HEADER_OUT: curl_infotype = 2; +pub const CURLINFO_DATA_IN: curl_infotype = 3; +pub const CURLINFO_DATA_OUT: curl_infotype = 4; +pub const CURLINFO_SSL_DATA_IN: curl_infotype = 5; +pub const CURLINFO_SSL_DATA_OUT: curl_infotype = 6; + +pub type curl_debug_callback = extern fn(*mut CURL, + curl_infotype, + *mut c_char, + size_t, + *mut c_void) -> c_int; + +pub const CURLE_OK: CURLcode = 0; +pub const CURLE_UNSUPPORTED_PROTOCOL: CURLcode = 1; +pub const CURLE_FAILED_INIT: CURLcode = 2; +pub const CURLE_URL_MALFORMAT: CURLcode = 3; +// pub const CURLE_NOT_BUILT_IN: CURLcode = 4; +pub const CURLE_COULDNT_RESOLVE_PROXY: CURLcode = 5; +pub const CURLE_COULDNT_RESOLVE_HOST: CURLcode = 6; +pub const CURLE_COULDNT_CONNECT: CURLcode = 7; +pub const CURLE_FTP_WEIRD_SERVER_REPLY: CURLcode = 8; +pub const CURLE_REMOTE_ACCESS_DENIED: CURLcode = 9; +// pub const CURLE_FTP_ACCEPT_FAILED: CURLcode = 10; +pub const CURLE_FTP_WEIRD_PASS_REPLY: CURLcode = 11; +// pub const CURLE_FTP_ACCEPT_TIMEOUT: CURLcode = 12; +pub const CURLE_FTP_WEIRD_PASV_REPLY: CURLcode = 13; +pub const CURLE_FTP_WEIRD_227_FORMAT: CURLcode = 14; +pub const CURLE_FTP_CANT_GET_HOST: CURLcode = 15; +pub const CURLE_OBSOLETE16: CURLcode = 16; +pub const CURLE_FTP_COULDNT_SET_TYPE: CURLcode = 17; +pub const CURLE_PARTIAL_FILE: CURLcode = 18; +pub const CURLE_FTP_COULDNT_RETR_FILE: CURLcode = 19; +pub const CURLE_OBSOLETE20: CURLcode = 20; +pub const CURLE_QUOTE_ERROR: CURLcode = 21; +pub const CURLE_HTTP_RETURNED_ERROR: CURLcode = 22; +pub const CURLE_WRITE_ERROR: CURLcode = 23; +pub const CURLE_OBSOLETE24: CURLcode = 24; +pub const CURLE_UPLOAD_FAILED: CURLcode = 25; +pub const CURLE_READ_ERROR: CURLcode = 26; +pub const CURLE_OUT_OF_MEMORY: CURLcode = 27; +pub const CURLE_OPERATION_TIMEDOUT: CURLcode = 28; +pub const CURLE_OBSOLETE29: CURLcode = 29; +pub const CURLE_FTP_PORT_FAILED: CURLcode = 30; +pub const CURLE_FTP_COULDNT_USE_REST: CURLcode = 31; +pub const CURLE_OBSOLETE32: CURLcode = 32; +pub const CURLE_RANGE_ERROR: CURLcode = 33; +pub const CURLE_HTTP_POST_ERROR: CURLcode = 34; +pub const CURLE_SSL_CONNECT_ERROR: CURLcode = 35; +pub const CURLE_BAD_DOWNLOAD_RESUME: CURLcode = 36; +pub const CURLE_FILE_COULDNT_READ_FILE: CURLcode = 37; +pub const CURLE_LDAP_CANNOT_BIND: CURLcode = 38; +pub const CURLE_LDAP_SEARCH_FAILED: CURLcode = 39; +pub const CURLE_OBSOLETE40: CURLcode = 40; +pub const CURLE_FUNCTION_NOT_FOUND: CURLcode = 41; +pub const CURLE_ABORTED_BY_CALLBACK: CURLcode = 42; +pub const CURLE_BAD_FUNCTION_ARGUMENT: CURLcode = 43; +pub const CURLE_OBSOLETE44: CURLcode = 44; +pub const CURLE_INTERFACE_FAILED: CURLcode = 45; +pub const CURLE_OBSOLETE46: CURLcode = 46; +pub const CURLE_TOO_MANY_REDIRECTS : CURLcode = 47; +pub const CURLE_UNKNOWN_OPTION: CURLcode = 48; +pub const CURLE_TELNET_OPTION_SYNTAX : CURLcode = 49; +pub const CURLE_OBSOLETE50: CURLcode = 50; +pub const CURLE_PEER_FAILED_VERIFICATION: CURLcode = 51; +pub const CURLE_GOT_NOTHING: CURLcode = 52; +pub const CURLE_SSL_ENGINE_NOTFOUND: CURLcode = 53; +pub const CURLE_SSL_ENGINE_SETFAILED: CURLcode = 54; +pub const CURLE_SEND_ERROR: CURLcode = 55; +pub const CURLE_RECV_ERROR: CURLcode = 56; +pub const CURLE_OBSOLETE57: CURLcode = 57; +pub const CURLE_SSL_CERTPROBLEM: CURLcode = 58; +pub const CURLE_SSL_CIPHER: CURLcode = 59; +pub const CURLE_SSL_CACERT: CURLcode = 60; +pub const CURLE_BAD_CONTENT_ENCODING: CURLcode = 61; +pub const CURLE_LDAP_INVALID_URL: CURLcode = 62; +pub const CURLE_FILESIZE_EXCEEDED: CURLcode = 63; +pub const CURLE_USE_SSL_FAILED: CURLcode = 64; +pub const CURLE_SEND_FAIL_REWIND: CURLcode = 65; +pub const CURLE_SSL_ENGINE_INITFAILED: CURLcode = 66; +pub const CURLE_LOGIN_DENIED: CURLcode = 67; +pub const CURLE_TFTP_NOTFOUND: CURLcode = 68; +pub const CURLE_TFTP_PERM: CURLcode = 69; +pub const CURLE_REMOTE_DISK_FULL: CURLcode = 70; +pub const CURLE_TFTP_ILLEGAL: CURLcode = 71; +pub const CURLE_TFTP_UNKNOWNID: CURLcode = 72; +pub const CURLE_REMOTE_FILE_EXISTS: CURLcode = 73; +pub const CURLE_TFTP_NOSUCHUSER: CURLcode = 74; +pub const CURLE_CONV_FAILED: CURLcode = 75; +pub const CURLE_CONV_REQD: CURLcode = 76; +pub const CURLE_SSL_CACERT_BADFILE: CURLcode = 77; +pub const CURLE_REMOTE_FILE_NOT_FOUND: CURLcode = 78; +pub const CURLE_SSH: CURLcode = 79; +pub const CURLE_SSL_SHUTDOWN_FAILED: CURLcode = 80; +pub const CURLE_AGAIN: CURLcode = 81; +pub const CURLE_SSL_CRL_BADFILE: CURLcode = 82; +pub const CURLE_SSL_ISSUER_ERROR: CURLcode = 83; +pub const CURLE_FTP_PRET_FAILED: CURLcode = 84; +pub const CURLE_RTSP_CSEQ_ERROR: CURLcode = 85; +pub const CURLE_RTSP_SESSION_ERROR: CURLcode = 86; +pub const CURLE_FTP_BAD_FILE_LIST: CURLcode = 87; +pub const CURLE_CHUNK_FAILED: CURLcode = 88; +// pub const CURLE_NO_CONNECTION_AVAILABLE: CURLcode = 89; + +pub type curl_conv_callback = extern fn(*mut c_char, size_t) -> CURLcode; +pub type curl_ssl_ctx_callback = extern fn(*mut CURL, + *mut c_void, + *mut c_void) -> CURLcode; + +pub type curl_proxytype = __enum_ty; +pub const CURLPROXY_HTTP: curl_proxytype = 0; +pub const CURLPROXY_HTTP_1_0: curl_proxytype = 1; +pub const CURLPROXY_SOCKS4: curl_proxytype = 4; +pub const CURLPROXY_SOCKS5: curl_proxytype = 5; +pub const CURLPROXY_SOCKS4A: curl_proxytype = 6; +pub const CURLPROXY_SOCKS5_HOSTNAME: curl_proxytype = 7; + +pub const CURLAUTH_NONE: c_ulong = 0; +pub const CURLAUTH_BASIC: c_ulong = 1 << 0; +pub const CURLAUTH_DIGEST: c_ulong = 1 << 1; +pub const CURLAUTH_GSSNEGOTIATE: c_ulong = 1 << 2; +pub const CURLAUTH_NTLM: c_ulong = 1 << 3; +pub const CURLAUTH_DIGEST_IE: c_ulong = 1 << 4; +pub const CURLAUTH_NTLM_WB: c_ulong = 1 << 5; +// pub const CURLAUTH_ONLY: c_ulong = 1 << 31; +pub const CURLAUTH_ANY: c_ulong = !CURLAUTH_DIGEST_IE; +pub const CURLAUTH_ANYSAFE: c_ulong = !(CURLAUTH_BASIC | CURLAUTH_DIGEST_IE); + +// pub const CURLSSH_AUTH_ANY: c_ulong = !0; +// pub const CURLSSH_AUTH_NONE: c_ulong = 0; +// pub const CURLSSH_AUTH_PUBLICKEY: c_ulong = 1 << 0; +// pub const CURLSSH_AUTH_PASSWORD: c_ulong = 1 << 1; +// pub const CURLSSH_AUTH_HOST: c_ulong = 1 << 2; +// pub const CURLSSH_AUTH_KEYBOARD: c_ulong = 1 << 3; +// pub const CURLSSH_AUTH_AGENT: c_ulong = 1 << 4; +// pub const CURLSSH_AUTH_DEFAULT: c_ulong = CURLSSH_AUTH_ANY; + +pub const CURLGSSAPI_DELEGATION_NONE: c_ulong = 0; +pub const CURLGSSAPI_DELEGATION_POLICY_FLAG: c_ulong = 1 << 0; +pub const CURLGSSAPI_DELEGATION_FLAG: c_ulong = 1 << 1; + +// pub type curl_khtype = __enum_ty; +// pub const CURLKHTYPE_UNKNOWN: curl_khtype = 0; +// pub const CURLKHTYPE_RSA1: curl_khtype = 1; +// pub const CURLKHTYPE_RSA: curl_khtype = 2; +// pub const CURLKHTYPE_DSS: curl_khtype = 3; + +// #[repr(C)] +// pub struct curl_khkey { +// pub key: *const c_char, +// pub len: size_t, +// pub keytype: curl_khtype, +// } + +// pub type curl_khstat = __enum_ty; +// pub const CURLKHSTAT_FINE_ADD_TO_FILE: curl_khstat = 0; +// pub const CURLKHSTAT_FINE: curl_khstat = 1; +// pub const CURLKHSTAT_REJECT: curl_khstat = 2; +// pub const CURLKHSTAT_DEFER: curl_khstat = 3; +// +// pub type curl_khmatch = __enum_ty; +// pub const CURLKHMATCH_OK: curl_khmatch = 0; +// pub const CURLKHMATCH_MISMATCH: curl_khmatch = 1; +// pub const CURLKHMATCH_MISSING: curl_khmatch = 2; + +// pub type curl_sshkeycallback = extern fn(*mut CURL, +// *const curl_khkey, +// *const curl_khkey, +// curl_khmatch, +// *mut c_void) -> c_int; + +pub const CURL_NETRC_IGNORED: c_ulong = 0; +pub const CURL_NETRC_OPTIONAL: c_ulong = 1; +pub const CURL_NETRC_REQUIRED: c_ulong = 2; + +pub type curl_usessl = __enum_ty; +pub const CURLUSESSL_NONE: curl_usessl = 0; +pub const CURLUSESSL_TRY: curl_usessl = 1; +pub const CURLUSESSL_CONTROL: curl_usessl = 2; +pub const CURLUSESSL_ALL: curl_usessl = 3; + +pub const CURLPROTO_HTTP: c_int = 1 << 0; +pub const CURLPROTO_HTTPS: c_int = 1 << 1; +pub const CURLPROTO_FILE: c_int = 1 << 10; + +pub const CURLOPTTYPE_LONG: CURLoption = 0; +pub const CURLOPTTYPE_OBJECTPOINT: CURLoption = 10_000; +pub const CURLOPTTYPE_FUNCTIONPOINT: CURLoption = 20_000; +pub const CURLOPTTYPE_OFF_T: CURLoption = 30_000; + +pub const CURLOPT_FILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 1; +pub const CURLOPT_URL: CURLoption = CURLOPTTYPE_OBJECTPOINT + 2; +pub const CURLOPT_PORT: CURLoption = CURLOPTTYPE_LONG + 3; +pub const CURLOPT_PROXY: CURLoption = CURLOPTTYPE_OBJECTPOINT + 4; +pub const CURLOPT_USERPWD: CURLoption = CURLOPTTYPE_OBJECTPOINT + 5; +pub const CURLOPT_PROXYUSERPWD: CURLoption = CURLOPTTYPE_OBJECTPOINT + 6; +pub const CURLOPT_RANGE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 7; +pub const CURLOPT_INFILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 9; +pub const CURLOPT_ERRORBUFFER: CURLoption = CURLOPTTYPE_OBJECTPOINT + 10; +pub const CURLOPT_WRITEFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 11; +pub const CURLOPT_READFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 12; +pub const CURLOPT_TIMEOUT: CURLoption = CURLOPTTYPE_LONG + 13; +pub const CURLOPT_INFILESIZE: CURLoption = CURLOPTTYPE_LONG + 14; +pub const CURLOPT_POSTFIELDS: CURLoption = CURLOPTTYPE_OBJECTPOINT + 15; +pub const CURLOPT_REFERER: CURLoption = CURLOPTTYPE_OBJECTPOINT + 16; +pub const CURLOPT_FTPPORT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 17; +pub const CURLOPT_USERAGENT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 18; +pub const CURLOPT_LOW_SPEED_LIMIT: CURLoption = CURLOPTTYPE_LONG + 19; +pub const CURLOPT_LOW_SPEED_TIME: CURLoption = CURLOPTTYPE_LONG + 20; +pub const CURLOPT_RESUME_FROM: CURLoption = CURLOPTTYPE_LONG + 21; +pub const CURLOPT_COOKIE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 22; +pub const CURLOPT_HTTPHEADER: CURLoption = CURLOPTTYPE_OBJECTPOINT + 23; +pub const CURLOPT_HTTPPOST: CURLoption = CURLOPTTYPE_OBJECTPOINT + 24; +pub const CURLOPT_SSLCERT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 25; +pub const CURLOPT_KEYPASSWD: CURLoption = CURLOPTTYPE_OBJECTPOINT + 26; +pub const CURLOPT_CRLF: CURLoption = CURLOPTTYPE_LONG + 27; +pub const CURLOPT_QUOTE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 28; +pub const CURLOPT_WRITEHEADER: CURLoption = CURLOPTTYPE_OBJECTPOINT + 29; +pub const CURLOPT_COOKIEFILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 31; +pub const CURLOPT_SSLVERSION: CURLoption = CURLOPTTYPE_LONG + 32; +pub const CURLOPT_TIMECONDITION: CURLoption = CURLOPTTYPE_LONG + 33; +pub const CURLOPT_TIMEVALUE: CURLoption = CURLOPTTYPE_LONG + 34; +pub const CURLOPT_CUSTOMREQUEST: CURLoption = CURLOPTTYPE_OBJECTPOINT + 36; +pub const CURLOPT_STDERR: CURLoption = CURLOPTTYPE_OBJECTPOINT + 37; +pub const CURLOPT_POSTQUOTE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 39; +pub const CURLOPT_WRITEINFO: CURLoption = CURLOPTTYPE_OBJECTPOINT + 40; +pub const CURLOPT_VERBOSE: CURLoption = CURLOPTTYPE_LONG + 41; +pub const CURLOPT_HEADER: CURLoption = CURLOPTTYPE_LONG + 42; +pub const CURLOPT_NOPROGRESS: CURLoption = CURLOPTTYPE_LONG + 43; +pub const CURLOPT_NOBODY: CURLoption = CURLOPTTYPE_LONG + 44; +pub const CURLOPT_FAILONERROR: CURLoption = CURLOPTTYPE_LONG + 45; +pub const CURLOPT_UPLOAD: CURLoption = CURLOPTTYPE_LONG + 46; +pub const CURLOPT_POST: CURLoption = CURLOPTTYPE_LONG + 47; +pub const CURLOPT_DIRLISTONLY: CURLoption = CURLOPTTYPE_LONG + 48; +pub const CURLOPT_APPEND: CURLoption = CURLOPTTYPE_LONG + 50; +pub const CURLOPT_NETRC: CURLoption = CURLOPTTYPE_LONG + 51; +pub const CURLOPT_FOLLOWLOCATION: CURLoption = CURLOPTTYPE_LONG + 52; +pub const CURLOPT_TRANSFERTEXT: CURLoption = CURLOPTTYPE_LONG + 53; +pub const CURLOPT_PUT: CURLoption = CURLOPTTYPE_LONG + 54; +pub const CURLOPT_PROGRESSFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 56; +pub const CURLOPT_PROGRESSDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 57; +pub const CURLOPT_AUTOREFERER: CURLoption = CURLOPTTYPE_LONG + 58; +pub const CURLOPT_PROXYPORT: CURLoption = CURLOPTTYPE_LONG + 59; +pub const CURLOPT_POSTFIELDSIZE: CURLoption = CURLOPTTYPE_LONG + 60; +pub const CURLOPT_HTTPPROXYTUNNEL: CURLoption = CURLOPTTYPE_LONG + 61; +pub const CURLOPT_INTERFACE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 62; +pub const CURLOPT_KRBLEVEL: CURLoption = CURLOPTTYPE_OBJECTPOINT + 63; +pub const CURLOPT_SSL_VERIFYPEER: CURLoption = CURLOPTTYPE_LONG + 64; +pub const CURLOPT_CAINFO: CURLoption = CURLOPTTYPE_OBJECTPOINT + 65; +pub const CURLOPT_MAXREDIRS: CURLoption = CURLOPTTYPE_LONG + 68; +pub const CURLOPT_FILETIME: CURLoption = CURLOPTTYPE_LONG + 69; +pub const CURLOPT_TELNETOPTIONS: CURLoption = CURLOPTTYPE_OBJECTPOINT + 70; +pub const CURLOPT_MAXCONNECTS: CURLoption = CURLOPTTYPE_LONG + 71; +pub const CURLOPT_CLOSEPOLICY: CURLoption = CURLOPTTYPE_LONG + 72; +pub const CURLOPT_FRESH_CONNECT: CURLoption = CURLOPTTYPE_LONG + 74; +pub const CURLOPT_FORBID_REUSE: CURLoption = CURLOPTTYPE_LONG + 75; +pub const CURLOPT_RANDOM_FILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 76; +pub const CURLOPT_EGDSOCKET: CURLoption = CURLOPTTYPE_OBJECTPOINT + 77; +pub const CURLOPT_CONNECTTIMEOUT: CURLoption = CURLOPTTYPE_LONG + 78; +pub const CURLOPT_HEADERFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 79; +pub const CURLOPT_HTTPGET: CURLoption = CURLOPTTYPE_LONG + 80; +pub const CURLOPT_SSL_VERIFYHOST: CURLoption = CURLOPTTYPE_LONG + 81; +pub const CURLOPT_COOKIEJAR: CURLoption = CURLOPTTYPE_OBJECTPOINT + 82; +pub const CURLOPT_SSL_CIPHER_LIST: CURLoption = CURLOPTTYPE_OBJECTPOINT + 83; +pub const CURLOPT_HTTP_VERSION: CURLoption = CURLOPTTYPE_LONG + 84; +pub const CURLOPT_FTP_USE_EPSV: CURLoption = CURLOPTTYPE_LONG + 85; +pub const CURLOPT_SSLCERTTYPE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 86; +pub const CURLOPT_SSLKEY: CURLoption = CURLOPTTYPE_OBJECTPOINT + 87; +pub const CURLOPT_SSLKEYTYPE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 88; +pub const CURLOPT_SSLENGINE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 89; +pub const CURLOPT_SSLENGINE_DEFAULT: CURLoption = CURLOPTTYPE_LONG + 90; +pub const CURLOPT_DNS_USE_GLOBAL_CACHE: CURLoption = CURLOPTTYPE_LONG + 91; +pub const CURLOPT_DNS_CACHE_TIMEOUT: CURLoption = CURLOPTTYPE_LONG + 92; +pub const CURLOPT_PREQUOTE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 93; +pub const CURLOPT_DEBUGFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 94; +pub const CURLOPT_DEBUGDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 95; +pub const CURLOPT_COOKIESESSION: CURLoption = CURLOPTTYPE_LONG + 96; +pub const CURLOPT_CAPATH: CURLoption = CURLOPTTYPE_OBJECTPOINT + 97; +pub const CURLOPT_BUFFERSIZE: CURLoption = CURLOPTTYPE_LONG + 98; +pub const CURLOPT_NOSIGNAL: CURLoption = CURLOPTTYPE_LONG + 99; +pub const CURLOPT_SHARE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 100; +pub const CURLOPT_PROXYTYPE: CURLoption = CURLOPTTYPE_LONG + 101; +pub const CURLOPT_ACCEPT_ENCODING: CURLoption = CURLOPTTYPE_OBJECTPOINT + 102; +pub const CURLOPT_PRIVATE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 103; +pub const CURLOPT_HTTP200ALIASES: CURLoption = CURLOPTTYPE_OBJECTPOINT + 104; +pub const CURLOPT_UNRESTRICTED_AUTH: CURLoption = CURLOPTTYPE_LONG + 105; +pub const CURLOPT_FTP_USE_EPRT: CURLoption = CURLOPTTYPE_LONG + 106; +pub const CURLOPT_HTTPAUTH: CURLoption = CURLOPTTYPE_LONG + 107; +pub const CURLOPT_SSL_CTX_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 108; +pub const CURLOPT_SSL_CTX_DATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 109; +pub const CURLOPT_FTP_CREATE_MISSING_DIRS: CURLoption = CURLOPTTYPE_LONG + 110; +pub const CURLOPT_PROXYAUTH: CURLoption = CURLOPTTYPE_LONG + 111; +pub const CURLOPT_FTP_RESPONSE_TIMEOUT: CURLoption = CURLOPTTYPE_LONG + 112; +pub const CURLOPT_IPRESOLVE: CURLoption = CURLOPTTYPE_LONG + 113; +pub const CURLOPT_MAXFILESIZE: CURLoption = CURLOPTTYPE_LONG + 114; +pub const CURLOPT_INFILESIZE_LARGE: CURLoption = CURLOPTTYPE_OFF_T + 115; +pub const CURLOPT_RESUME_FROM_LARGE: CURLoption = CURLOPTTYPE_OFF_T + 116; +pub const CURLOPT_MAXFILESIZE_LARGE: CURLoption = CURLOPTTYPE_OFF_T + 117; +pub const CURLOPT_NETRC_FILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 118; +pub const CURLOPT_USE_SSL: CURLoption = CURLOPTTYPE_LONG + 119; +pub const CURLOPT_POSTFIELDSIZE_LARGE: CURLoption = CURLOPTTYPE_OFF_T + 120; +pub const CURLOPT_TCP_NODELAY: CURLoption = CURLOPTTYPE_LONG + 121; +pub const CURLOPT_FTPSSLAUTH: CURLoption = CURLOPTTYPE_LONG + 129; +pub const CURLOPT_IOCTLFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 130; +pub const CURLOPT_IOCTLDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 131; +pub const CURLOPT_FTP_ACCOUNT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 134; +pub const CURLOPT_COOKIELIST: CURLoption = CURLOPTTYPE_OBJECTPOINT + 135; +pub const CURLOPT_IGNORE_CONTENT_LENGTH: CURLoption = CURLOPTTYPE_LONG + 136; +pub const CURLOPT_FTP_SKIP_PASV_IP: CURLoption = CURLOPTTYPE_LONG + 137; +pub const CURLOPT_FTP_FILEMETHOD: CURLoption = CURLOPTTYPE_LONG + 138; +pub const CURLOPT_LOCALPORT: CURLoption = CURLOPTTYPE_LONG + 139; +pub const CURLOPT_LOCALPORTRANGE: CURLoption = CURLOPTTYPE_LONG + 140; +pub const CURLOPT_CONNECT_ONLY: CURLoption = CURLOPTTYPE_LONG + 141; +pub const CURLOPT_CONV_FROM_NETWORK_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 142; +pub const CURLOPT_CONV_TO_NETWORK_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 143; +pub const CURLOPT_CONV_FROM_UTF8_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 144; +pub const CURLOPT_MAX_SEND_SPEED_LARGE: CURLoption = CURLOPTTYPE_OFF_T + 145; +pub const CURLOPT_MAX_RECV_SPEED_LARGE: CURLoption = CURLOPTTYPE_OFF_T + 146; +pub const CURLOPT_FTP_ALTERNATIVE_TO_USER: CURLoption = CURLOPTTYPE_OBJECTPOINT + 147; +pub const CURLOPT_SOCKOPTFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 148; +pub const CURLOPT_SOCKOPTDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 149; +pub const CURLOPT_SSL_SESSIONID_CACHE: CURLoption = CURLOPTTYPE_LONG + 150; +pub const CURLOPT_SSH_AUTH_TYPES: CURLoption = CURLOPTTYPE_LONG + 151; +pub const CURLOPT_SSH_PUBLIC_KEYFILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 152; +pub const CURLOPT_SSH_PRIVATE_KEYFILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 153; +pub const CURLOPT_FTP_SSL_CCC: CURLoption = CURLOPTTYPE_LONG + 154; +pub const CURLOPT_TIMEOUT_MS: CURLoption = CURLOPTTYPE_LONG + 155; +pub const CURLOPT_CONNECTTIMEOUT_MS: CURLoption = CURLOPTTYPE_LONG + 156; +pub const CURLOPT_HTTP_TRANSFER_DECODING: CURLoption = CURLOPTTYPE_LONG + 157; +pub const CURLOPT_HTTP_CONTENT_DECODING: CURLoption = CURLOPTTYPE_LONG + 158; +pub const CURLOPT_NEW_FILE_PERMS: CURLoption = CURLOPTTYPE_LONG + 159; +pub const CURLOPT_NEW_DIRECTORY_PERMS: CURLoption = CURLOPTTYPE_LONG + 160; +pub const CURLOPT_POSTREDIR: CURLoption = CURLOPTTYPE_LONG + 161; +pub const CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: CURLoption = CURLOPTTYPE_OBJECTPOINT + 162; +pub const CURLOPT_OPENSOCKETFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 163; +pub const CURLOPT_OPENSOCKETDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 164; +pub const CURLOPT_COPYPOSTFIELDS: CURLoption = CURLOPTTYPE_OBJECTPOINT + 165; +pub const CURLOPT_PROXY_TRANSFER_MODE: CURLoption = CURLOPTTYPE_LONG + 166; +pub const CURLOPT_SEEKFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 167; +pub const CURLOPT_SEEKDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 168; +pub const CURLOPT_CRLFILE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 169; +pub const CURLOPT_ISSUERCERT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 170; +pub const CURLOPT_ADDRESS_SCOPE: CURLoption = CURLOPTTYPE_LONG + 171; +pub const CURLOPT_CERTINFO: CURLoption = CURLOPTTYPE_LONG + 172; +pub const CURLOPT_USERNAME: CURLoption = CURLOPTTYPE_OBJECTPOINT + 173; +pub const CURLOPT_PASSWORD: CURLoption = CURLOPTTYPE_OBJECTPOINT + 174; +pub const CURLOPT_PROXYUSERNAME: CURLoption = CURLOPTTYPE_OBJECTPOINT + 175; +pub const CURLOPT_PROXYPASSWORD: CURLoption = CURLOPTTYPE_OBJECTPOINT + 176; +pub const CURLOPT_NOPROXY: CURLoption = CURLOPTTYPE_OBJECTPOINT + 177; +pub const CURLOPT_TFTP_BLKSIZE: CURLoption = CURLOPTTYPE_LONG + 178; +pub const CURLOPT_SOCKS5_GSSAPI_SERVICE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 179; +pub const CURLOPT_SOCKS5_GSSAPI_NEC: CURLoption = CURLOPTTYPE_LONG + 180; +pub const CURLOPT_PROTOCOLS: CURLoption = CURLOPTTYPE_LONG + 181; +pub const CURLOPT_REDIR_PROTOCOLS: CURLoption = CURLOPTTYPE_LONG + 182; +pub const CURLOPT_SSH_KNOWNHOSTS: CURLoption = CURLOPTTYPE_OBJECTPOINT + 183; +pub const CURLOPT_SSH_KEYFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 184; +pub const CURLOPT_SSH_KEYDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 185; +pub const CURLOPT_MAIL_FROM: CURLoption = CURLOPTTYPE_OBJECTPOINT + 186; +pub const CURLOPT_MAIL_RCPT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 187; +pub const CURLOPT_FTP_USE_PRET: CURLoption = CURLOPTTYPE_LONG + 188; +pub const CURLOPT_RTSP_REQUEST: CURLoption = CURLOPTTYPE_LONG + 189; +pub const CURLOPT_RTSP_SESSION_ID: CURLoption = CURLOPTTYPE_OBJECTPOINT + 190; +pub const CURLOPT_RTSP_STREAM_URI: CURLoption = CURLOPTTYPE_OBJECTPOINT + 191; +pub const CURLOPT_RTSP_TRANSPORT: CURLoption = CURLOPTTYPE_OBJECTPOINT + 192; +pub const CURLOPT_RTSP_CLIENT_CSEQ: CURLoption = CURLOPTTYPE_LONG + 193; +pub const CURLOPT_RTSP_SERVER_CSEQ: CURLoption = CURLOPTTYPE_LONG + 194; +pub const CURLOPT_INTERLEAVEDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 195; +pub const CURLOPT_INTERLEAVEFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 196; +pub const CURLOPT_WILDCARDMATCH: CURLoption = CURLOPTTYPE_LONG + 197; +pub const CURLOPT_CHUNK_BGN_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 198; +pub const CURLOPT_CHUNK_END_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 199; +pub const CURLOPT_FNMATCH_FUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 200; +pub const CURLOPT_CHUNK_DATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 201; +pub const CURLOPT_FNMATCH_DATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 202; +pub const CURLOPT_RESOLVE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 203; +pub const CURLOPT_TLSAUTH_USERNAME: CURLoption = CURLOPTTYPE_OBJECTPOINT + 204; +pub const CURLOPT_TLSAUTH_PASSWORD: CURLoption = CURLOPTTYPE_OBJECTPOINT + 205; +pub const CURLOPT_TLSAUTH_TYPE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 206; +pub const CURLOPT_TRANSFER_ENCODING: CURLoption = CURLOPTTYPE_LONG + 207; +pub const CURLOPT_CLOSESOCKETFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 208; +pub const CURLOPT_CLOSESOCKETDATA: CURLoption = CURLOPTTYPE_OBJECTPOINT + 209; +pub const CURLOPT_GSSAPI_DELEGATION: CURLoption = CURLOPTTYPE_LONG + 210; +// pub const CURLOPT_DNS_SERVERS: CURLoption = CURLOPTTYPE_OBJECTPOINT + 211; +// pub const CURLOPT_ACCEPTTIMEOUT_MS: CURLoption = CURLOPTTYPE_LONG + 212; +pub const CURLOPT_TCP_KEEPALIVE: CURLoption = CURLOPTTYPE_LONG + 213; +pub const CURLOPT_TCP_KEEPIDLE: CURLoption = CURLOPTTYPE_LONG + 214; +pub const CURLOPT_TCP_KEEPINTVL: CURLoption = CURLOPTTYPE_LONG + 215; +pub const CURLOPT_SSL_OPTIONS: CURLoption = CURLOPTTYPE_LONG + 216; +// pub const CURLOPT_MAIL_AUTH: CURLoption = CURLOPTTYPE_OBJECTPOINT + 217; +// pub const CURLOPT_SASL_IR: CURLoption = CURLOPTTYPE_LONG + 218; +// pub const CURLOPT_XFERINFOFUNCTION: CURLoption = CURLOPTTYPE_FUNCTIONPOINT + 219; +// pub const CURLOPT_XOAUTH2_BEARER: CURLoption = CURLOPTTYPE_OBJECTPOINT + 220; +// pub const CURLOPT_DNS_INTERFACE: CURLoption = CURLOPTTYPE_OBJECTPOINT + 221; +// pub const CURLOPT_DNS_LOCAL_IP4: CURLoption = CURLOPTTYPE_OBJECTPOINT + 222; +// pub const CURLOPT_DNS_LOCAL_IP6: CURLoption = CURLOPTTYPE_OBJECTPOINT + 223; +// pub const CURLOPT_LOGIN_OPTIONS: CURLoption = CURLOPTTYPE_OBJECTPOINT + 224; +pub const CURLOPT_UNIX_SOCKET_PATH: CURLoption = CURLOPTTYPE_OBJECTPOINT + 231; + +pub const CURL_IPRESOLVE_WHATEVER: c_int = 0; +pub const CURL_IPRESOLVE_V4: c_int = 1; +pub const CURL_IPRESOLVE_V6: c_int = 2; + +pub const CURLSSLOPT_ALLOW_BEAST: c_long = 1 << 0; +pub const CURLSSLOPT_NO_REVOKE: c_long = 1 << 1; + +/// These enums are for use with the CURLOPT_HTTP_VERSION option. +/// +/// Setting this means we don't care, and that we'd like the library to choose +/// the best possible for us! +pub const CURL_HTTP_VERSION_NONE: c_int = 0; +/// Please use HTTP 1.0 in the request +pub const CURL_HTTP_VERSION_1_0: c_int = 1; +/// Please use HTTP 1.1 in the request +pub const CURL_HTTP_VERSION_1_1: c_int = 2; +/// Please use HTTP 2 in the request +/// (Added in CURL 7.33.0) +pub const CURL_HTTP_VERSION_2_0: c_int = 3; +/// Use version 2 for HTTPS, version 1.1 for HTTP +/// (Added in CURL 7.47.0) +pub const CURL_HTTP_VERSION_2TLS: c_int = 4; +/// Please use HTTP 2 without HTTP/1.1 Upgrade +/// (Added in CURL 7.49.0) +pub const CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE: c_int = 5; + +// Note that the type here is wrong, it's just intended to just be an enum. +pub const CURL_SSLVERSION_DEFAULT: CURLoption = 0; +pub const CURL_SSLVERSION_TLSv1: CURLoption = 1; +pub const CURL_SSLVERSION_SSLv2: CURLoption = 2; +pub const CURL_SSLVERSION_SSLv3: CURLoption = 3; +// pub const CURL_SSLVERSION_TLSv1_0: CURLoption = 4; +// pub const CURL_SSLVERSION_TLSv1_1: CURLoption = 5; +// pub const CURL_SSLVERSION_TLSv1_2: CURLoption = 6; + +pub const CURLOPT_READDATA: CURLoption = CURLOPT_INFILE; +pub const CURLOPT_WRITEDATA: CURLoption = CURLOPT_FILE; +pub const CURLOPT_HEADERDATA: CURLoption = CURLOPT_WRITEHEADER; + +pub type curl_TimeCond = __enum_ty; +pub const CURL_TIMECOND_NONE: curl_TimeCond = 0; +pub const CURL_TIMECOND_IFMODSINCE: curl_TimeCond = 1; +pub const CURL_TIMECOND_IFUNMODSINCE: curl_TimeCond = 2; +pub const CURL_TIMECOND_LASTMOD: curl_TimeCond = 3; + +pub type CURLformoption = __enum_ty; +pub const CURLFORM_NOTHING: CURLformoption = 0; +pub const CURLFORM_COPYNAME: CURLformoption = 1; +pub const CURLFORM_PTRNAME: CURLformoption = 2; +pub const CURLFORM_NAMELENGTH: CURLformoption = 3; +pub const CURLFORM_COPYCONTENTS: CURLformoption = 4; +pub const CURLFORM_PTRCONTENTS: CURLformoption = 5; +pub const CURLFORM_CONTENTSLENGTH: CURLformoption = 6; +pub const CURLFORM_FILECONTENT: CURLformoption = 7; +pub const CURLFORM_ARRAY: CURLformoption = 8; +pub const CURLFORM_OBSOLETE: CURLformoption = 9; +pub const CURLFORM_FILE: CURLformoption = 10; +pub const CURLFORM_BUFFER: CURLformoption = 11; +pub const CURLFORM_BUFFERPTR: CURLformoption = 12; +pub const CURLFORM_BUFFERLENGTH: CURLformoption = 13; +pub const CURLFORM_CONTENTTYPE: CURLformoption = 14; +pub const CURLFORM_CONTENTHEADER: CURLformoption = 15; +pub const CURLFORM_FILENAME: CURLformoption = 16; +pub const CURLFORM_END: CURLformoption = 17; +pub const CURLFORM_STREAM: CURLformoption = 19; + +pub type CURLFORMcode = __enum_ty; +pub const CURL_FORMADD_OK: CURLFORMcode = 0; +pub const CURL_FORMADD_MEMORY: CURLFORMcode = 1; +pub const CURL_FORMADD_OPTION_TWICE: CURLFORMcode = 2; +pub const CURL_FORMADD_NULL: CURLFORMcode = 3; +pub const CURL_FORMADD_UNKNOWN_OPTION: CURLFORMcode = 4; +pub const CURL_FORMADD_INCOMPLETE: CURLFORMcode = 5; +pub const CURL_FORMADD_ILLEGAL_ARRAY: CURLFORMcode = 6; +pub const CURL_FORMADD_DISABLED: CURLFORMcode = 7; + +#[repr(C)] +pub struct curl_forms { + pub option: CURLformoption, + pub value: *const c_char, +} + +pub type curl_formget_callback = extern fn(*mut c_void, + *const c_char, + size_t) -> size_t; + +#[repr(C)] +pub struct curl_slist { + pub data: *mut c_char, + pub next: *mut curl_slist, +} + +#[repr(C)] +pub struct curl_certinfo { + pub num_of_certs: c_int, + pub certinfo: *mut *mut curl_slist, +} + +// pub type curl_sslbackend = __enum_ty; +// pub const CURLSSLBACKEND_NONE: curl_sslbackend = 0; +// pub const CURLSSLBACKEND_OPENSSL: curl_sslbackend = 1; +// pub const CURLSSLBACKEND_GNUTLS: curl_sslbackend = 2; +// pub const CURLSSLBACKEND_NSS: curl_sslbackend = 3; +// pub const CURLSSLBACKEND_QSOSSL: curl_sslbackend = 4; +// pub const CURLSSLBACKEND_GSKIT: curl_sslbackend = 5; +// pub const CURLSSLBACKEND_POLARSSL: curl_sslbackend = 6; +// pub const CURLSSLBACKEND_CYASSL: curl_sslbackend = 7; +// pub const CURLSSLBACKEND_SCHANNEL: curl_sslbackend = 8; +// pub const CURLSSLBACKEND_DARWINSSL: curl_sslbackend = 9; + +// #[repr(C)] +// pub struct curl_tlssessioninfo { +// pub backend: curl_sslbackend, +// pub internals: *mut c_void, +// } + +pub const CURLINFO_STRING: CURLINFO = 0x100000; +pub const CURLINFO_LONG: CURLINFO = 0x200000; +pub const CURLINFO_DOUBLE: CURLINFO = 0x300000; +pub const CURLINFO_SLIST: CURLINFO = 0x400000; +pub const CURLINFO_MASK: CURLINFO = 0x0fffff; +pub const CURLINFO_TYPEMASK: CURLINFO = 0xf00000; + +pub const CURLINFO_EFFECTIVE_URL: CURLINFO = CURLINFO_STRING + 1; +pub const CURLINFO_RESPONSE_CODE: CURLINFO = CURLINFO_LONG + 2; +pub const CURLINFO_TOTAL_TIME: CURLINFO = CURLINFO_DOUBLE + 3; +pub const CURLINFO_NAMELOOKUP_TIME: CURLINFO = CURLINFO_DOUBLE + 4; +pub const CURLINFO_CONNECT_TIME: CURLINFO = CURLINFO_DOUBLE + 5; +pub const CURLINFO_PRETRANSFER_TIME: CURLINFO = CURLINFO_DOUBLE + 6; +pub const CURLINFO_SIZE_UPLOAD: CURLINFO = CURLINFO_DOUBLE + 7; +pub const CURLINFO_SIZE_DOWNLOAD: CURLINFO = CURLINFO_DOUBLE + 8; +pub const CURLINFO_SPEED_DOWNLOAD: CURLINFO = CURLINFO_DOUBLE + 9; +pub const CURLINFO_SPEED_UPLOAD: CURLINFO = CURLINFO_DOUBLE + 10; +pub const CURLINFO_HEADER_SIZE: CURLINFO = CURLINFO_LONG + 11; +pub const CURLINFO_REQUEST_SIZE: CURLINFO = CURLINFO_LONG + 12; +pub const CURLINFO_SSL_VERIFYRESULT: CURLINFO = CURLINFO_LONG + 13; +pub const CURLINFO_FILETIME: CURLINFO = CURLINFO_LONG + 14; +pub const CURLINFO_CONTENT_LENGTH_DOWNLOAD: CURLINFO = CURLINFO_DOUBLE + 15; +pub const CURLINFO_CONTENT_LENGTH_UPLOAD: CURLINFO = CURLINFO_DOUBLE + 16; +pub const CURLINFO_STARTTRANSFER_TIME: CURLINFO = CURLINFO_DOUBLE + 17; +pub const CURLINFO_CONTENT_TYPE: CURLINFO = CURLINFO_STRING + 18; +pub const CURLINFO_REDIRECT_TIME: CURLINFO = CURLINFO_DOUBLE + 19; +pub const CURLINFO_REDIRECT_COUNT: CURLINFO = CURLINFO_LONG + 20; +pub const CURLINFO_PRIVATE: CURLINFO = CURLINFO_STRING + 21; +pub const CURLINFO_HTTP_CONNECTCODE: CURLINFO = CURLINFO_LONG + 22; +pub const CURLINFO_HTTPAUTH_AVAIL: CURLINFO = CURLINFO_LONG + 23; +pub const CURLINFO_PROXYAUTH_AVAIL: CURLINFO = CURLINFO_LONG + 24; +pub const CURLINFO_OS_ERRNO: CURLINFO = CURLINFO_LONG + 25; +pub const CURLINFO_NUM_CONNECTS: CURLINFO = CURLINFO_LONG + 26; +pub const CURLINFO_SSL_ENGINES: CURLINFO = CURLINFO_SLIST + 27; +pub const CURLINFO_COOKIELIST: CURLINFO = CURLINFO_SLIST + 28; +pub const CURLINFO_LASTSOCKET: CURLINFO = CURLINFO_LONG + 29; +pub const CURLINFO_FTP_ENTRY_PATH: CURLINFO = CURLINFO_STRING + 30; +pub const CURLINFO_REDIRECT_URL: CURLINFO = CURLINFO_STRING + 31; +pub const CURLINFO_PRIMARY_IP: CURLINFO = CURLINFO_STRING + 32; +pub const CURLINFO_APPCONNECT_TIME: CURLINFO = CURLINFO_DOUBLE + 33; +pub const CURLINFO_CERTINFO: CURLINFO = CURLINFO_SLIST + 34; +pub const CURLINFO_CONDITION_UNMET: CURLINFO = CURLINFO_LONG + 35; +pub const CURLINFO_RTSP_SESSION_ID: CURLINFO = CURLINFO_STRING + 36; +pub const CURLINFO_RTSP_CLIENT_CSEQ: CURLINFO = CURLINFO_LONG + 37; +pub const CURLINFO_RTSP_SERVER_CSEQ: CURLINFO = CURLINFO_LONG + 38; +pub const CURLINFO_RTSP_CSEQ_RECV: CURLINFO = CURLINFO_LONG + 39; +pub const CURLINFO_PRIMARY_PORT: CURLINFO = CURLINFO_LONG + 40; +pub const CURLINFO_LOCAL_IP: CURLINFO = CURLINFO_STRING + 41; +pub const CURLINFO_LOCAL_PORT: CURLINFO = CURLINFO_LONG + 42; +// pub const CURLINFO_TLS_SESSION: CURLINFO = CURLINFO_SLIST + 43; + +pub type curl_closepolicy = __enum_ty; +pub const CURLCLOSEPOLICY_NONE: curl_closepolicy = 0; +pub const CURLCLOSEPOLICY_OLDEST: curl_closepolicy = 1; +pub const CURLCLOSEPOLICY_LEAST_RECENTLY_USED: curl_closepolicy = 2; +pub const CURLCLOSEPOLICY_LEAST_TRAFFIC: curl_closepolicy = 3; +pub const CURLCLOSEPOLICY_SLOWEST: curl_closepolicy = 4; +pub const CURLCLOSEPOLICY_CALLBACK: curl_closepolicy = 5; + +pub const CURL_GLOBAL_SSL: c_long = 1 << 0; +pub const CURL_GLOBAL_WIN32: c_long = 1 << 1; +pub const CURL_GLOBAL_ALL: c_long = CURL_GLOBAL_SSL | CURL_GLOBAL_WIN32; +pub const CURL_GLOBAL_NOTHING: c_long = 0; +pub const CURL_GLOBAL_DEFAULT: c_long = CURL_GLOBAL_ALL; +// pub const CURL_GLOBAL_ACK_EINTR: c_long = 1 << 2; + +pub type curl_lock_data = __enum_ty; +pub const CURL_LOCK_DATA_NONE: curl_lock_data = 0; +pub const CURL_LOCK_DATA_SHARE: curl_lock_data = 1; +pub const CURL_LOCK_DATA_COOKIE: curl_lock_data = 2; +pub const CURL_LOCK_DATA_DNS: curl_lock_data = 3; +pub const CURL_LOCK_DATA_SSL_SESSION: curl_lock_data = 4; +pub const CURL_LOCK_DATA_CONNECT: curl_lock_data = 5; + +pub type curl_lock_access = __enum_ty; +pub const CURL_LOCK_ACCESS_NONE: curl_lock_access = 0; +pub const CURL_LOCK_ACCESS_SHARED: curl_lock_access = 1; +pub const CURL_LOCK_ACCESS_SINGLE: curl_lock_access = 2; + +pub type curl_lock_function = extern fn(*mut CURL, + curl_lock_data, + curl_lock_access, + *mut c_void); +pub type curl_unlock_function = extern fn(*mut CURL, + curl_lock_data, + *mut c_void); + +pub enum CURLSH {} + +pub type CURLSHcode = __enum_ty; +pub const CURLSHE_OK: CURLSHcode = 0; +pub const CURLSHE_BAD_OPTION: CURLSHcode = 1; +pub const CURLSHE_IN_USE: CURLSHcode = 2; +pub const CURLSHE_INVALID: CURLSHcode = 3; +pub const CURLSHE_NOMEM: CURLSHcode = 4; +// pub const CURLSHE_NOT_BUILT_IN: CURLSHcode = 5; + +pub type CURLSHoption = __enum_ty; +pub const CURLSHOPT_NONE: CURLSHoption = 0; +pub const CURLSHOPT_SHARE: CURLSHoption = 1; +pub const CURLSHOPT_UNSHARE: CURLSHoption = 2; +pub const CURLSHOPT_LOCKFUNC: CURLSHoption = 3; +pub const CURLSHOPT_UNLOCKFUNC: CURLSHoption = 4; +pub const CURLSHOPT_USERDATA: CURLSHoption = 5; + +pub const CURLVERSION_FIRST: CURLversion = 0; +pub const CURLVERSION_SECOND: CURLversion = 1; +pub const CURLVERSION_THIRD: CURLversion = 2; +pub const CURLVERSION_FOURTH: CURLversion = 3; +pub const CURLVERSION_NOW: CURLversion = CURLVERSION_FOURTH; + +#[repr(C)] +pub struct curl_version_info_data { + pub age: CURLversion, + pub version: *const c_char, + pub version_num: c_uint, + pub host: *const c_char, + pub features: c_int, + pub ssl_version: *const c_char, + pub ssl_version_num: c_long, + pub libz_version: *const c_char, + pub protocols: *const *const c_char, + pub ares: *const c_char, + pub ares_num: c_int, + pub libidn: *const c_char, + pub iconv_ver_num: c_int, + pub libssh_version: *const c_char, +} + +pub const CURL_VERSION_IPV6: c_int = 1 << 0; +pub const CURL_VERSION_KERBEROS4: c_int = 1 << 1; +pub const CURL_VERSION_SSL: c_int = 1 << 2; +pub const CURL_VERSION_LIBZ: c_int = 1 << 3; +pub const CURL_VERSION_NTLM: c_int = 1 << 4; +pub const CURL_VERSION_GSSNEGOTIATE: c_int = 1 << 5; +pub const CURL_VERSION_DEBUG: c_int = 1 << 6; +pub const CURL_VERSION_ASYNCHDNS: c_int = 1 << 7; +pub const CURL_VERSION_SPNEGO: c_int = 1 << 8; +pub const CURL_VERSION_LARGEFILE: c_int = 1 << 9; +pub const CURL_VERSION_IDN: c_int = 1 << 10; +pub const CURL_VERSION_SSPI: c_int = 1 << 11; +pub const CURL_VERSION_CONV: c_int = 1 << 12; +pub const CURL_VERSION_CURLDEBUG: c_int = 1 << 13; +pub const CURL_VERSION_TLSAUTH_SRP: c_int = 1 << 14; +pub const CURL_VERSION_NTLM_WB: c_int = 1 << 15; +// pub const CURL_VERSION_HTTP2: c_int = 1 << 16; +pub const CURL_VERSION_UNIX_SOCKETS: c_int = 1 << 19; + +pub const CURLPAUSE_RECV: c_int = 1 << 0; +pub const CURLPAUSE_RECV_CONT: c_int = 0; +pub const CURLPAUSE_SEND: c_int = 1 << 2; +pub const CURLPAUSE_SEND_CONT: c_int = 0; + +pub enum CURLM {} + +pub type CURLMcode = c_int; +pub const CURLM_CALL_MULTI_PERFORM: CURLMcode = -1; +pub const CURLM_OK: CURLMcode = 0; +pub const CURLM_BAD_HANDLE: CURLMcode = 1; +pub const CURLM_BAD_EASY_HANDLE: CURLMcode = 2; +pub const CURLM_OUT_OF_MEMORY: CURLMcode = 3; +pub const CURLM_INTERNAL_ERROR: CURLMcode = 4; +pub const CURLM_BAD_SOCKET: CURLMcode = 5; +pub const CURLM_UNKNOWN_OPTION: CURLMcode = 6; +// pub const CURLM_ADDED_ALREADY: CURLMcode = 7; + +pub type CURLMSG = __enum_ty; +pub const CURLMSG_NONE: CURLMSG = 0; +pub const CURLMSG_DONE: CURLMSG = 1; + +#[repr(C)] +pub struct CURLMsg { + pub msg: CURLMSG, + pub easy_handle: *mut CURL, + pub data: *mut c_void, +} + +pub const CURL_WAIT_POLLIN: c_short = 0x1; +pub const CURL_WAIT_POLLPRI: c_short = 0x2; +pub const CURL_WAIT_POLLOUT: c_short = 0x4; + +#[repr(C)] +pub struct curl_waitfd { + pub fd: curl_socket_t, + pub events: c_short, + pub revents: c_short, +} + +pub const CURL_POLL_NONE: c_int = 0; +pub const CURL_POLL_IN: c_int = 1; +pub const CURL_POLL_OUT: c_int = 2; +pub const CURL_POLL_INOUT: c_int = 3; +pub const CURL_POLL_REMOVE: c_int = 4; +pub const CURL_CSELECT_IN: c_int = 1; +pub const CURL_CSELECT_OUT: c_int = 2; +pub const CURL_CSELECT_ERR: c_int = 4; +pub const CURL_SOCKET_TIMEOUT: curl_socket_t = CURL_SOCKET_BAD; + +pub type curl_socket_callback = extern fn(*mut CURL, + curl_socket_t, + c_int, + *mut c_void, + *mut c_void) -> c_int; +pub type curl_multi_timer_callback = extern fn(*mut CURLM, + c_long, + *mut c_void) -> c_int; + +pub type CURLMoption = __enum_ty; +pub const CURLMOPT_SOCKETFUNCTION: CURLMoption = CURLOPTTYPE_FUNCTIONPOINT + 1; +pub const CURLMOPT_SOCKETDATA: CURLMoption = CURLOPTTYPE_OBJECTPOINT + 2; +pub const CURLMOPT_PIPELINING: CURLMoption = CURLOPTTYPE_LONG + 3; +pub const CURLMOPT_TIMERFUNCTION: CURLMoption = CURLOPTTYPE_FUNCTIONPOINT + 4; +pub const CURLMOPT_TIMERDATA: CURLMoption = CURLOPTTYPE_OBJECTPOINT + 5; +// pub const CURLMOPT_MAXCONNECTS: CURLMoption = CURLOPTTYPE_LONG + 6; +// pub const CURLMOPT_MAX_HOST_CONNECTIONS: CURLMoption = CURLOPTTYPE_LONG + 7; +// pub const CURLMOPT_MAX_PIPELINE_LENGTH: CURLMoption = CURLOPTTYPE_LONG + 8; +// pub const CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE: CURLMoption = CURLOPTTYPE_OFF_T + 9; +// pub const CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE: CURLMoption = CURLOPTTYPE_OFF_T + 10; +// pub const CURLMOPT_PIPELINING_SITE_BL: CURLMoption = CURLOPTTYPE_OBJECTPOINT + 11; +// pub const CURLMOPT_PIPELINING_SERVER_BL: CURLMoption = CURLOPTTYPE_OBJECTPOINT + 12; +// pub const CURLMOPT_MAX_TOTAL_CONNECTIONS: CURLMoption = CURLOPTTYPE_LONG + 13; + +pub const CURL_ERROR_SIZE: usize = 256; + +pub type curl_opensocket_callback = extern fn(*mut c_void, + curlsocktype, + *mut curl_sockaddr) -> curl_socket_t; +pub type curlsocktype = __enum_ty; +pub const CURLSOCKTYPE_IPCXN: curlsocktype = 0; +pub const CURLSOCKTYPE_ACCEPT: curlsocktype = 1; +pub const CURLSOCKTYPE_LAST: curlsocktype = 2; + +#[repr(C)] +pub struct curl_sockaddr { + pub family: c_int, + pub socktype: c_int, + pub protocol: c_int, + pub addrlen: c_uint, + #[cfg(unix)] + pub addr: libc::sockaddr, + #[cfg(windows)] + pub addr: SOCKADDR, +} + +extern { + pub fn curl_formadd(httppost: *mut *mut curl_httppost, + last_post: *mut *mut curl_httppost, + ...) -> CURLFORMcode; + pub fn curl_formget(form: *mut curl_httppost, + arg: *mut c_void, + append: curl_formget_callback) -> c_int; + pub fn curl_formfree(form: *mut curl_httppost); + + pub fn curl_version() -> *mut c_char; + + pub fn curl_easy_escape(handle: *mut CURL, + string: *const c_char, + length: c_int) -> *mut c_char; + pub fn curl_easy_unescape(handle: *mut CURL, + string: *const c_char, + length: c_int, + outlength: *mut c_int) -> *mut c_char; + pub fn curl_free(p: *mut c_void); + + pub fn curl_global_init(flags: c_long) -> CURLcode; + pub fn curl_global_init_mem(flags: c_long, + m: curl_malloc_callback, + f: curl_free_callback, + r: curl_realloc_callback, + s: curl_strdup_callback, + c: curl_calloc_callback) -> CURLcode; + pub fn curl_global_cleanup(); + + pub fn curl_slist_append(list: *mut curl_slist, + val: *const c_char) -> *mut curl_slist; + pub fn curl_slist_free_all(list: *mut curl_slist); + + pub fn curl_getdate(p: *const c_char, _: *const time_t) -> time_t; + + pub fn curl_share_init() -> *mut CURLSH; + pub fn curl_share_setopt(sh: *mut CURLSH, + opt: CURLSHoption, + ...) -> CURLSHcode; + pub fn curl_share_cleanup(sh: *mut CURLSH) -> CURLSHcode; + + pub fn curl_version_info(t: CURLversion) -> *mut curl_version_info_data; + + pub fn curl_easy_strerror(code: CURLcode) -> *const c_char; + pub fn curl_share_strerror(code: CURLSHcode) -> *const c_char; + pub fn curl_easy_pause(handle: *mut CURL, bitmask: c_int) -> CURLcode; + + pub fn curl_easy_init() -> *mut CURL; + pub fn curl_easy_setopt(curl: *mut CURL, option: CURLoption, ...) -> CURLcode; + pub fn curl_easy_perform(curl: *mut CURL) -> CURLcode; + pub fn curl_easy_cleanup(curl: *mut CURL); + pub fn curl_easy_getinfo(curl: *mut CURL, info: CURLINFO, ...) -> CURLcode; + pub fn curl_easy_duphandle(curl: *mut CURL) -> *mut CURL; + pub fn curl_easy_reset(curl: *mut CURL); + pub fn curl_easy_recv(curl: *mut CURL, + buffer: *mut c_void, + buflen: size_t, + n: *mut size_t) -> CURLcode; + pub fn curl_easy_send(curl: *mut CURL, + buffer: *const c_void, + buflen: size_t, + n: *mut size_t) -> CURLcode; + + pub fn curl_multi_init() -> *mut CURLM; + pub fn curl_multi_add_handle(multi_handle: *mut CURLM, + curl_handle: *mut CURL) -> CURLMcode; + pub fn curl_multi_remove_handle(multi_handle: *mut CURLM, + curl_handle: *mut CURL) -> CURLMcode; + pub fn curl_multi_fdset(multi_handle: *mut CURLM, + read_fd_set: *mut fd_set, + write_fd_set: *mut fd_set, + exc_fd_set: *mut fd_set, + max_fd: *mut c_int) -> CURLMcode; + pub fn curl_multi_wait(multi_handle: *mut CURLM, + extra_fds: *mut curl_waitfd, + extra_nfds: c_uint, + timeout_ms: c_int, + ret: *mut c_int) -> CURLMcode; + pub fn curl_multi_perform(multi_handle: *mut CURLM, + running_handles: *mut c_int) -> CURLMcode; + pub fn curl_multi_cleanup(multi_handle: *mut CURLM) -> CURLMcode; + pub fn curl_multi_info_read(multi_handle: *mut CURLM, + msgs_in_queue: *mut c_int) -> *mut CURLMsg; + pub fn curl_multi_strerror(code: CURLMcode) -> *const c_char; + pub fn curl_multi_socket(multi_handle: *mut CURLM, + s: curl_socket_t, + running_handles: *mut c_int) -> CURLMcode; + pub fn curl_multi_socket_action(multi_handle: *mut CURLM, + s: curl_socket_t, + ev_bitmask: c_int, + running_handles: *mut c_int) -> CURLMcode; + pub fn curl_multi_socket_all(multi_handle: *mut CURLM, + running_handles: *mut c_int) -> CURLMcode; + pub fn curl_multi_timeout(multi_handle: *mut CURLM, + milliseconds: *mut c_long) -> CURLMcode; + pub fn curl_multi_setopt(multi_handle: *mut CURLM, + option: CURLMoption, + ...) -> CURLMcode; + pub fn curl_multi_assign(multi_handle: *mut CURLM, + sockfd: curl_socket_t, + sockp: *mut c_void) -> CURLMcode; +} diff --git a/docopt-0.8.3/.cargo-checksum.json b/docopt-0.8.3/.cargo-checksum.json new file mode 100644 index 000000000..101fd3b60 --- /dev/null +++ b/docopt-0.8.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"d8acd393692c503b168471874953a2531df0e9ab77d0b6bbc582395743300a4a"} \ No newline at end of file diff --git a/docopt-0.8.3/.travis.yml b/docopt-0.8.3/.travis.yml new file mode 100644 index 000000000..2f375d7c6 --- /dev/null +++ b/docopt-0.8.3/.travis.yml @@ -0,0 +1,15 @@ +language: rust +rust: + - 1.15.0 + - stable + - beta + - nightly +script: + - cargo build --verbose + - cargo test --verbose + - cargo doc + - if [ "$TRAVIS_RUST_VERSION" = "nightly" ]; then + cd docopt_macros; + cargo build --verbose; + cargo test --verbose; + fi diff --git a/docopt-0.8.3/COPYING b/docopt-0.8.3/COPYING new file mode 100644 index 000000000..bb9c20a09 --- /dev/null +++ b/docopt-0.8.3/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/docopt-0.8.3/Cargo.toml b/docopt-0.8.3/Cargo.toml new file mode 100644 index 000000000..e8141be60 --- /dev/null +++ b/docopt-0.8.3/Cargo.toml @@ -0,0 +1,47 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "docopt" +version = "0.8.3" +authors = ["Andrew Gallant "] +description = "Command line argument parsing." +homepage = "https://github.com/docopt/docopt.rs" +documentation = "http://burntsushi.net/rustdoc/docopt/" +readme = "README.md" +keywords = ["docopt", "argument", "command", "argv"] +categories = ["command-line-interface"] +license = "Unlicense/MIT" +repository = "https://github.com/docopt/docopt.rs" + +[lib] +name = "docopt" + +[[bin]] +name = "docopt-wordlist" +path = "src/wordlist.rs" +test = false +doc = false +[dependencies.lazy_static] +version = "1" + +[dependencies.regex] +version = "0.2" + +[dependencies.serde] +version = "1.0" + +[dependencies.serde_derive] +version = "1.0" + +[dependencies.strsim] +version = "0.6" diff --git a/docopt-0.8.3/LICENSE-MIT b/docopt-0.8.3/LICENSE-MIT new file mode 100644 index 000000000..3b0a5dc09 --- /dev/null +++ b/docopt-0.8.3/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/docopt-0.8.3/Makefile b/docopt-0.8.3/Makefile new file mode 100644 index 000000000..30ededbf0 --- /dev/null +++ b/docopt-0.8.3/Makefile @@ -0,0 +1,18 @@ +all: + @echo Nothing to do + +docs: $(LIB_FILES) + cargo doc + # WTF is rustdoc doing? + in-dir ./target/doc fix-perms + rscp ./target/doc/* gopher:~/www/burntsushi.net/rustdoc/ + +src/test/testcases.rs: src/test/testcases.docopt scripts/mk-testcases + ./scripts/mk-testcases ./src/test/testcases.docopt > ./src/test/testcases.rs + +ctags: + ctags --recurse --options=ctags.rust --languages=Rust + +push: + git push github master + git push origin master diff --git a/docopt-0.8.3/README.md b/docopt-0.8.3/README.md new file mode 100644 index 000000000..cc80c8bb1 --- /dev/null +++ b/docopt-0.8.3/README.md @@ -0,0 +1,357 @@ +Docopt for Rust with automatic type based decoding (i.e., data validation). +This implementation conforms to the +[official description of Docopt](http://docopt.org/) and +[passes its test suite](https://github.com/docopt/docopt/pull/201). + +[![Build status](https://api.travis-ci.org/docopt/docopt.rs.svg)](https://travis-ci.org/docopt/docopt.rs) +[![](http://meritbadge.herokuapp.com/docopt)](https://crates.io/crates/docopt) + +Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). + + +### Current status + +Fully functional but the design of the API is up for debate. **I am seeking +feedback**. + + +### Documentation + + + + +### Installation + +This crate is fully compatible with Cargo. Just add it to your `Cargo.toml`: + +```toml +[dependencies] +docopt = "0.8" +serde = "1.0" # if you're using `derive(Deserialize)` +serde_derive = "1.0" # if you're using `derive(Deserialize)` +``` + +If you want to use the macro, then add `docopt_macros = "0.8"` instead. +Note that the **`docopt!` macro only works on a nightly Rust compiler** because +it is a compiler plugin. + + +### Quick example + +Here is a full working example. Notice that you can specify the types of each +of the named values in the Docopt usage string. Values will be automatically +converted to those types (or an error will be reported). + +```rust +#[macro_use] +extern crate serde_derive; +extern crate docopt; + +use docopt::Docopt; + +const USAGE: &'static str = " +Naval Fate. + +Usage: + naval_fate.py ship new ... + naval_fate.py ship move [--speed=] + naval_fate.py ship shoot + naval_fate.py mine (set|remove) [--moored | --drifting] + naval_fate.py (-h | --help) + naval_fate.py --version + +Options: + -h --help Show this screen. + --version Show version. + --speed= Speed in knots [default: 10]. + --moored Moored (anchored) mine. + --drifting Drifting mine. +"; + +#[derive(Debug, Deserialize)] +struct Args { + flag_speed: isize, + flag_drifting: bool, + arg_name: Vec, + arg_x: Option, + arg_y: Option, + cmd_ship: bool, + cmd_mine: bool, +} + +fn main() { + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + println!("{:?}", args); +} +``` + +Here is the same example, but with the use of the `docopt!` macro, which will +*generate a struct for you*. Note that this uses a compiler plugin, so it only +works on a **nightly Rust compiler**: + +```rust +#![feature(plugin)] +#![plugin(docopt_macros)] + +#[macro_use] +extern crate serde_derive; +extern crate docopt; + +use docopt::Docopt; + +docopt!(Args derive Debug, " +Naval Fate. + +Usage: + naval_fate.py ship new ... + naval_fate.py ship move [--speed=] + naval_fate.py ship shoot + naval_fate.py mine (set|remove) [--moored | --drifting] + naval_fate.py (-h | --help) + naval_fate.py --version + +Options: + -h --help Show this screen. + --version Show version. + --speed= Speed in knots [default: 10]. + --moored Moored (anchored) mine. + --drifting Drifting mine. +"); + +fn main() { + let args: Args = Args::docopt().deserialize().unwrap_or_else(|e| e.exit()); + println!("{:?}", args); +} +``` + +The `Args` struct has one static method defined for it: `docopt`. The method +returns a normal `Docopt` value, which can be used to set configuration +options, `argv` and parse or decode command line arguments. + + +### Struct field name mapping + +The field names of the struct map like this: + +``` +-g => flag_g +--group => flag_group +--group => flag_group +FILE => arg_FILE + => arg_file +build => cmd_build +``` + + +### Data validation example + +Here's another example that shows how to specify the types of your arguments: + +```rust +#![feature(plugin)] +#![plugin(docopt_macros)] + +#[macro_use] +extern crate serde_derive; + +extern crate docopt; + +docopt!(Args, "Usage: add ", arg_x: i32, arg_y: i32); + +fn main() { + let args: Args = Args::docopt().deserialize().unwrap_or_else(|e| e.exit()); + println!("x: {}, y: {}", args.arg_x, args.arg_y); +} +``` + +In this example, specific type annotations were added. They will be +automatically inserted into the generated struct. You can override as many (or +as few) fields as you want. If you don't specify a type, then one of `bool`, +`u64`, `String` or `Vec` will be chosen depending on the type of +argument. In this case, both `arg_x` and `arg_y` would have been `String`. + +If any value cannot be decoded into a value with the right type, then an error +will be shown to the user. + +And of course, you don't need the macro to do this. You can do the same thing +with a manually written struct too. + + +### Modeling `rustc` + +Here's a selected subset for some of `rustc`'s options. This also shows how to +restrict values to a list of choices via an `enum` type and demonstrates more +Docopt features. + +```rust +#![feature(plugin)] +#![plugin(docopt_macros)] + +#[macro_use] +extern crate serde_derive; +extern crate serde; + +extern crate docopt; + +use serde::de; + +docopt!(Args derive Debug, " +Usage: rustc [options] [--cfg SPEC... -L PATH...] INPUT + rustc (--help | --version) + +Options: + -h, --help Show this message. + --version Show the version of rustc. + --cfg SPEC Configure the compilation environment. + -L PATH Add a directory to the library search path. + --emit TYPE Configure the output that rustc will produce. + Valid values: asm, ir, bc, obj, link. + --opt-level LEVEL Optimize with possible levels 0-3. +", flag_opt_level: Option, flag_emit: Option); + +#[derive(Deserialize, Debug)] +enum Emit { Asm, Ir, Bc, Obj, Link } + +#[derive(Debug)] +enum OptLevel { Zero, One, Two, Three } + +impl<'de> de::Deserialize<'de> for OptLevel { + fn deserialize(deserializer: D) -> Result + where D: de::Deserializer<'de> + { + let level = match u8::deserialize(deserializer)? { + 0 => OptLevel::Zero, + 1 => OptLevel::One, + 2 => OptLevel::Two, + 3 => OptLevel::Three, + n => { + let value = de::Unexpected::Unsigned(n as u64); + let msg = "expected an integer between 0 and 3"; + return Err(de::Error::invalid_value(value, &msg)); + } + }; + Ok(level) + } +} + +fn main() { + let args: Args = Args::docopt().deserialize().unwrap_or_else(|e| e.exit()); + println!("{:?}", args); +} +``` + +### Viewing the generated struct + +Generating a struct is pretty magical, but if you want, you can look at it by +expanding all macros. Say you wrote the above example for `Usage: add ` +into a file called `add.rs`. Then running: + +```bash +rustc -L path/containing/docopt/lib -Z unstable-options --pretty=expanded add.rs +``` + +Will show all macros expanded. The `path/containing/docopt/lib` is usually +`target/debug/deps` or `target/release/deps` in a cargo project. In the generated code, you should be +able to find the generated struct: + +```rust +struct Args { + pub arg_x: int, + pub arg_y: int, +} +``` + + +### Traditional Docopt API + +The reference implementation of Docopt returns a Python dictionary with names +like `` or `--flag`. If you prefer this access pattern, then you can use +`docopt::ArgvMap`. The disadvantage is that you have to do all of your type +conversion manually. Here's the canonical Docopt example with a hash table: + +```rust +extern crate docopt; + +use docopt::Docopt; + +const USAGE: &'static str = " +Naval Fate. + +Usage: + naval_fate.py ship new ... + naval_fate.py ship move [--speed=] + naval_fate.py ship shoot + naval_fate.py mine (set|remove) [--moored | --drifting] + naval_fate.py (-h | --help) + naval_fate.py --version + +Options: + -h --help Show this screen. + --version Show version. + --speed= Speed in knots [default: 10]. + --moored Moored (anchored) mine. + --drifting Drifting mine. +"; + +fn main() { + let args = Docopt::new(USAGE) + .and_then(|dopt| dopt.parse()) + .unwrap_or_else(|e| e.exit()); + println!("{:?}", args); + + // You can conveniently access values with `get_{bool,count,str,vec}` + // functions. If the key doesn't exist (or if, e.g., you use `get_str` on + // a switch), then a sensible default value is returned. + println!("\nSome values:"); + println!(" Speed: {}", args.get_str("--speed")); + println!(" Drifting? {}", args.get_bool("--drifting")); + println!(" Names: {:?}", args.get_vec("")); +} +``` + +### Tab completion support + +This particular implementation bundles a command called `docopt-wordlist` that +can be used to automate tab completion. This repository also collects some +basic completion support for various shells (currently only bash) in the +`completions` directory. + +You can use them to setup tab completion on your system. It should work with +any program that uses Docopt (or rather, any program that outputs usage +messages that look like Docopt). For example, to get tab completion support for +Cargo, you'll have to install `docopt-wordlist` and add some voodoo to your +`$HOME/.bash_completion` file (this may vary for other shells). + +Here it is step by step: + +```bash +# Download and build `docopt-wordlist` (as part of the Docopt package) +$ git clone git://github.com/docopt/docopt.rs +$ cd docopt.rs +$ cargo build --release + +# Now setup tab completion (for bash) +$ echo "DOCOPT_WORDLIST_BIN=\"$(pwd)/target/release/docopt-wordlist\"" >> $HOME/.bash_completion +$ echo "source \"$(pwd)/completions/docopt-wordlist.bash\"" >> $HOME/.bash_completion +$ echo "complete -F _docopt_wordlist_commands cargo" >> $HOME/.bash_completion +``` + +My [CSV toolkit](https://github.com/BurntSushi/xsv) is supported too: + +```bash +# shameless plug... +$ echo "complete -F _docopt_wordlist_commands xsv" >> $HOME/.bash_completion +``` + +Note that this is emphatically a first pass. There are several improvements +that I'd like to make: + +1. Take context into account when completing. For example, it should be + possible to only show completions that can lead to a valid Docopt match. + This may be hard. (i.e., It may require restructuring Docopt's internals.) +2. Support more shells. (I'll happily accept pull requests on this one. I doubt + I'll venture outside of bash any time soon.) +3. Make tab completion support more seamless. The way it works right now is + pretty hacky by intermingling file/directory completion. diff --git a/docopt-0.8.3/UNLICENSE b/docopt-0.8.3/UNLICENSE new file mode 100644 index 000000000..68a49daad --- /dev/null +++ b/docopt-0.8.3/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/docopt-0.8.3/completions/docopt-wordlist.bash b/docopt-0.8.3/completions/docopt-wordlist.bash new file mode 100644 index 000000000..9033a20d3 --- /dev/null +++ b/docopt-0.8.3/completions/docopt-wordlist.bash @@ -0,0 +1,79 @@ +# This is your basic tab completion that will work well with commands that +# have only one usage (i.e., no distinct sub-commands). +# +# Completion works by simply taking the command name and running `$cmd --help` +# to get the usage (which is then parsed for possible completions). +function _docopt_wordlist { + if [ -z "$DOCOPT_WORDLIST_BIN" ]; then + DOCOPT_WORDLIST_BIN=/usr/local/bin/docopt-wordlist + fi + + cword=$(_get_cword) + cmd="${COMP_WORDS[0]}" + wordlist=$("$cmd" --help 2>&1 | "$DOCOPT_WORDLIST_BIN") + gen "$cword" "$wordlist" +} + +# This is a fancier version of the above that supports commands that have +# multiple sub-commands (i.e., distinct usages like Cargo). +# +# This supports sub-command completion only if `$cmd --list` shows a list of +# available sub-commands. +# +# Otherwise, the usage for the command `a b c d` is taken from the first +# command that exits successfully: +# +# a b c d --help +# a b c --help +# a b --help +# a --help +# +# So for example, if you've typed `cargo test --jo`, then the following +# happens: +# +# cargo test --jo --help # error +# cargo test --help # gives 'test' sub-command usage! +# +# As a special case, if only the initial command has been typed, then the +# sub-commands (taken from `$cmd --list`) are added to the wordlist. +function _docopt_wordlist_commands { + if [ -z "$DOCOPT_WORDLIST_BIN" ]; then + DOCOPT_WORDLIST_BIN=/usr/local/bin/docopt-wordlist + fi + + cword=$(_get_cword) + if [ "$COMP_CWORD" = 1 ]; then + cmd="${COMP_WORDS[0]}" + wordlist=$("$cmd" --help 2>&1 | "$DOCOPT_WORDLIST_BIN") + wordlist+=" $("$cmd" --list | egrep '^ +\w' | awk '{print $1}')" + gen "$cword" "$wordlist" + else + for ((i="$COMP_CWORD"; i >= 1; i++)); do + cmd="${COMP_WORDS[@]::$i}" + wordlist=$($cmd --help 2>&1 | "$DOCOPT_WORDLIST_BIN") + if [ $? = 0 ]; then + gen "$cword" "$wordlist" + break + fi + done + fi +} + +# A helper function for running `compgen`, which is responsible for taking +# a prefix and presenting possible completions. +# +# If the current prefix starts with a `.` or a `/`, then file/directory +# completion is done. Otherwise, Docopt completion is done. If Docopt +# completion is empty, then it falls back to file/directory completion. +function gen { + cword="$1" + wordlist="$2" + if [[ "$cword" = .* || "$cword" = /* ]]; then + COMPREPLY=($(compgen -A file -- "$cword")) + else + COMPREPLY=($(compgen -W "$wordlist" -- "$cword")) + if [ -z "$COMPREPLY" ]; then + COMPREPLY=($(compgen -A file -- "$cword")) + fi + fi +} diff --git a/docopt-0.8.3/ctags.rust b/docopt-0.8.3/ctags.rust new file mode 100644 index 000000000..b42edf757 --- /dev/null +++ b/docopt-0.8.3/ctags.rust @@ -0,0 +1,11 @@ +--langdef=Rust +--langmap=Rust:.rs +--regex-Rust=/^[ \t]*(#\[[^\]]\][ \t]*)*(pub[ \t]+)?(extern[ \t]+)?("[^"]+"[ \t]+)?(unsafe[ \t]+)?fn[ \t]+([a-zA-Z0-9_]+)/\6/f,functions,function definitions/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?type[ \t]+([a-zA-Z0-9_]+)/\2/T,types,type definitions/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?enum[ \t]+([a-zA-Z0-9_]+)/\2/g,enum,enumeration names/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?struct[ \t]+([a-zA-Z0-9_]+)/\2/s,structure names/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?mod[ \t]+([a-zA-Z0-9_]+)/\2/m,modules,module names/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?static[ \t]+([a-zA-Z0-9_]+)/\2/c,consts,static constants/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?trait[ \t]+([a-zA-Z0-9_]+)/\2/t,traits,traits/ +--regex-Rust=/^[ \t]*(pub[ \t]+)?impl([ \t\n]+<.*>)?[ \t]+([a-zA-Z0-9_]+)/\3/i,impls,trait implementations/ +--regex-Rust=/^[ \t]*macro_rules![ \t]+([a-zA-Z0-9_]+)/\1/d,macros,macro definitions/ diff --git a/docopt-0.8.3/examples/cargo.rs b/docopt-0.8.3/examples/cargo.rs new file mode 100644 index 000000000..abc135de0 --- /dev/null +++ b/docopt-0.8.3/examples/cargo.rs @@ -0,0 +1,59 @@ +#[macro_use] +extern crate serde_derive; +extern crate docopt; + +use docopt::Docopt; + +// Write the Docopt usage string. +const USAGE: &'static str = " +Rust's package manager + +Usage: + cargo [...] + cargo [options] + +Options: + -h, --help Display this message + -V, --version Print version info and exit + --list List installed commands + -v, --verbose Use verbose output + +Some common cargo commands are: + build Compile the current project + clean Remove the target directory + doc Build this project's and its dependencies' documentation + new Create a new cargo project + run Build and execute src/main.rs + test Run the tests + bench Run the benchmarks + update Update dependencies listed in Cargo.lock + +See 'cargo help ' for more information on a specific command. +"; + +#[derive(Debug, Deserialize)] +struct Args { + arg_command: Option, + arg_args: Vec, + flag_list: bool, + flag_verbose: bool, +} + +#[derive(Debug, Deserialize)] +enum Command { + Build, + Clean, + Doc, + New, + Run, + Test, + Bench, + Update, +} + +fn main() { + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.options_first(true).deserialize()) + .unwrap_or_else(|e| e.exit()); + println!("{:?}", args); +} diff --git a/docopt-0.8.3/examples/cp.rs b/docopt-0.8.3/examples/cp.rs new file mode 100644 index 000000000..b2380249f --- /dev/null +++ b/docopt-0.8.3/examples/cp.rs @@ -0,0 +1,29 @@ +#[macro_use] +extern crate serde_derive; +extern crate docopt; + +use docopt::Docopt; + +// Write the Docopt usage string. +const USAGE: &'static str = " +Usage: cp [-a] + cp [-a] ... + +Options: + -a, --archive Copy everything. +"; + +#[derive(Debug, Deserialize)] +struct Args { + arg_source: Vec, + arg_dest: String, + arg_dir: String, + flag_archive: bool, +} + +fn main() { + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + println!("{:?}", args); +} diff --git a/docopt-0.8.3/examples/decode.rs b/docopt-0.8.3/examples/decode.rs new file mode 100644 index 000000000..1a1a36281 --- /dev/null +++ b/docopt-0.8.3/examples/decode.rs @@ -0,0 +1,48 @@ +#[macro_use] +extern crate serde_derive; +extern crate docopt; + +use docopt::Docopt; + +const USAGE: &'static str = " +Naval Fate. + +Usage: + naval_fate.py ship new ... + naval_fate.py ship move [--speed=] + naval_fate.py ship shoot + naval_fate.py mine (set|remove) [--moored | --drifting] + naval_fate.py (-h | --help) + naval_fate.py --version + +Options: + -h --help Show this screen. + --version Show version. + --speed= Speed in knots [default: 10]. + --moored Moored (anchored) mine. + --drifting Drifting mine. +"; + +#[derive(Debug, Deserialize)] +struct Args { + flag_speed: isize, + flag_drifting: bool, + arg_name: Vec, + arg_x: Option, + arg_y: Option, + cmd_ship: bool, + cmd_mine: bool, +} + +fn main() { + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + println!("{:?}", args); + + println!("\nSome values:"); + println!(" Speed: {}", args.flag_speed); + println!(" Drifting? {}", args.flag_drifting); + println!(" Names: {:?}", args.arg_name); + println!(" Command 'ship' invoked? {:?}", args.cmd_ship); +} diff --git a/docopt-0.8.3/examples/hashmap.rs b/docopt-0.8.3/examples/hashmap.rs new file mode 100644 index 000000000..8d8a3f38f --- /dev/null +++ b/docopt-0.8.3/examples/hashmap.rs @@ -0,0 +1,39 @@ +extern crate docopt; + +use docopt::Docopt; + +const USAGE: &'static str = " +Naval Fate. + +Usage: + naval_fate.py ship new ... + naval_fate.py ship move [--speed=] + naval_fate.py ship shoot + naval_fate.py mine (set|remove) [--moored | --drifting] + naval_fate.py (-h | --help) + naval_fate.py --version + +Options: + -h --help Show this screen. + --version Show version. + --speed= Speed in knots [default: 10]. + --moored Moored (anchored) mine. + --drifting Drifting mine. +"; + +fn main() { + let version = "1.2.3".to_owned(); + let args = Docopt::new(USAGE) + .and_then(|dopt| dopt.version(Some(version)).parse()) + .unwrap_or_else(|e| e.exit()); + println!("{:?}", args); + + // You can conveniently access values with `get_{bool,count,str,vec}` + // functions. If the key doesn't exist (or if, e.g., you use `get_str` on + // a switch), then a sensible default value is returned. + println!("\nSome values:"); + println!(" Speed: {}", args.get_str("--speed")); + println!(" Drifting? {}", args.get_bool("--drifting")); + println!(" Names: {:?}", args.get_vec("")); + println!(" Command 'ship' invoked? {:?}", args.get_bool("ship")); +} diff --git a/docopt-0.8.3/examples/optional_command.rs b/docopt-0.8.3/examples/optional_command.rs new file mode 100644 index 000000000..1039653f6 --- /dev/null +++ b/docopt-0.8.3/examples/optional_command.rs @@ -0,0 +1,76 @@ +// This example shows how to implement a command with a "catch all." +// +// This requires writing your own impl for `Decodable` because docopt's +// decoder uses `Option` to mean "T may not be present" rather than +// "T may be present but incorrect." + +#[macro_use] +extern crate serde_derive; +extern crate serde; +extern crate docopt; + +use docopt::Docopt; +use serde::de::{Deserialize, Deserializer, Error, Visitor}; +use std::fmt; + +// Write the Docopt usage string. +const USAGE: &'static str = " +Rust's package manager + +Usage: + mycli [] + +Options: + -h, --help Display this message +"; + +#[derive(Debug, Deserialize)] +struct Args { + arg_command: Command, +} + +struct CommandVisitor; + +impl<'de> Visitor<'de> for CommandVisitor { + type Value = Command; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string A, B or C") + } + + fn visit_str(self, s: &str) -> Result + where E: Error + { + Ok(match s { + "" => Command::None, + "A" => Command::A, + "B" => Command::B, + "C" => Command::C, + s => Command::Unknown(s.to_string()), + }) + } +} + +impl<'de> Deserialize<'de> for Command { + fn deserialize(d: D) -> Result + where D: Deserializer<'de> + { + d.deserialize_str(CommandVisitor) + } +} + +#[derive(Debug)] +enum Command { + A, + B, + C, + Unknown(String), + None, +} + +fn main() { + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + println!("{:?}", args); +} diff --git a/docopt-0.8.3/examples/verbose_multiple.rs b/docopt-0.8.3/examples/verbose_multiple.rs new file mode 100644 index 000000000..298bdae23 --- /dev/null +++ b/docopt-0.8.3/examples/verbose_multiple.rs @@ -0,0 +1,37 @@ +#[macro_use] +extern crate serde_derive; +extern crate docopt; + +use docopt::Docopt; + +// This shows how to implement multiple levels of verbosity. +// +// When you have multiple patterns, I think the only way to carry the +// repeated flag through all of them is to specify it for each pattern +// explicitly. +// +// This is unfortunate. +const USAGE: &'static str = " +Usage: cp [options] [-v | -vv | -vvv] + cp [options] [-v | -vv | -vvv] ... + +Options: + -a, --archive Copy everything. + -v, --verbose Show extra log output. +"; + +#[derive(Debug, Deserialize)] +struct Args { + arg_source: Vec, + arg_dest: String, + arg_dir: String, + flag_archive: bool, + flag_verbose: usize, +} + +fn main() { + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + println!("{:?}", args); +} diff --git a/docopt-0.8.3/scripts/mk-testcases b/docopt-0.8.3/scripts/mk-testcases new file mode 100755 index 000000000..9f4f78347 --- /dev/null +++ b/docopt-0.8.3/scripts/mk-testcases @@ -0,0 +1,80 @@ +#!/usr/bin/env python2 + +from __future__ import absolute_import, division, print_function +import argparse +import json +import re + +retests = re.compile('(.*?)"""(.*?)(r"""|\s*$)', re.DOTALL) +reinvokes = re.compile('(.+?$)(.+?)\s*(\$|\Z)', re.DOTALL | re.MULTILINE) + +p = argparse.ArgumentParser( + description="Outputs src/test/testcases.rs to stdout") +p.add_argument("testcases", metavar="FILE", + help="The testcases.docopt language agnostic test suite.") +args = p.parse_args() + +with open(args.testcases) as f: + alltests = f.read() + +alltests = re.sub('^r"""', '', alltests) +alltests = re.sub('^\s*#.*$', '', alltests, flags=re.MULTILINE) + +tests = [] # [{usage, args, expect}] (expect is None ==> user-error) +for m in retests.finditer(alltests): + usage, invokes = m.group(1).strip(), m.group(2).strip() + assert invokes.startswith('$'), 'Bad test: "%s"' % invokes + invokes = re.sub('^\$', '', invokes) + + for mi in reinvokes.finditer(invokes): + invoke, expect = mi.group(1).strip(), mi.group(2).strip() + err = expect.startswith('"user-error"') + tests.append({ + 'usage': usage, + 'args': invoke.split()[1:], + 'expect': None if err else json.loads(expect), + }) + + +def show_test(i, t): + def show_expect(e): + kvs = [] + for k, v in e.iteritems(): + kvs.append('("%s", %s)' % (k, show_value(v))) + return ', '.join(kvs) + def show_value(v): + if v is None: + return 'Plain(None)' + elif isinstance(v, basestring): + return 'Plain(Some("%s".to_string()))' % v + elif isinstance(v, bool): + return 'Switch(%s)' % ('true' if v else 'false') + elif isinstance(v, int): + return 'Counted(%d)' % v + elif isinstance(v, list): + elms = ', '.join(['"%s".to_string()' % el for el in v]) + return 'List(vec!(%s))' % elms + else: + raise ValueError('Unrecognized value: "%s" (type: %s)' + % (v, type(v))) + + args = ', '.join(['"%s"' % arg for arg in t['args']]) + if t['expect'] is None: + return 'test_user_error!(test_%d_testcases, "%s", &[%s]);' \ + % (i, t['usage'], args) + else: + expect = show_expect(t['expect']) + return 'test_expect!(test_%d_testcases, "%s", &[%s], vec!(%s));' \ + % (i, t['usage'], args, expect) + +print( +"""// !!! ATTENTION !!! +// This file is automatically generated by `scripts/mk-testcases`. +// Please do not edit this file directly! + +use Value::{{Switch, Counted, Plain, List}}; +use test::{{get_args, map_from_alist, same_args}}; + +{tests} +""".format(tests='\n\n'.join([show_test(i, t) for i, t in enumerate(tests)]))) + diff --git a/docopt-0.8.3/session.vim b/docopt-0.8.3/session.vim new file mode 100644 index 000000000..59eea67a1 --- /dev/null +++ b/docopt-0.8.3/session.vim @@ -0,0 +1,3 @@ +au BufWritePost *.rs silent!make ctags > /dev/null 2>&1 +" let g:syntastic_rust_rustc_fname = "src/lib.rs" +" let g:syntastic_rust_rustc_args = "--no-trans" diff --git a/docopt-0.8.3/src/dopt.rs b/docopt-0.8.3/src/dopt.rs new file mode 100644 index 000000000..9c803023d --- /dev/null +++ b/docopt-0.8.3/src/dopt.rs @@ -0,0 +1,1006 @@ +use std::collections::HashMap; +use std::error::Error as StdError; +use std::fmt::{self, Debug}; +use std::io::{self, Write}; +use std::str::FromStr; +use std::result; + +use regex::{Captures, Regex}; +use serde::de; +use serde::de::IntoDeserializer; + +use parse::Parser; +use synonym::SynonymMap; + +use self::Value::{Switch, Counted, Plain, List}; +use self::Error::{Usage, Argv, NoMatch, Deserialize, WithProgramUsage, Help, Version}; + +use cap_or_empty; + +/// Represents the different types of Docopt errors. +/// +/// This error type has a lot of variants. In the common case, you probably +/// don't care why Docopt has failed, and would rather just quit the program +/// and show an error message instead. The `exit` method defined on the `Error` +/// type will do just that. It will also set the exit code appropriately +/// (no error for `--help` or `--version`, but an error code for bad usage, +/// bad argv, no match or bad decode). +/// +/// ### Example +/// +/// Generally, you want to parse the usage string, try to match the argv +/// and then quit the program if there was an error reported at any point +/// in that process. This can be achieved like so: +/// +/// ```no_run +/// use docopt::Docopt; +/// +/// const USAGE: &'static str = " +/// Usage: ... +/// "; +/// +/// let args = Docopt::new(USAGE) +/// .and_then(|d| d.parse()) +/// .unwrap_or_else(|e| e.exit()); +/// ``` +#[derive(Debug)] +pub enum Error { + /// Parsing the usage string failed. + /// + /// This error can only be triggered by the programmer, i.e., the writer + /// of the Docopt usage string. This error is usually indicative of a bug + /// in your program. + Usage(String), + + /// Parsing the argv specified failed. + /// + /// The payload is a string describing why the arguments provided could not + /// be parsed. + /// + /// This is distinct from `NoMatch` because it will catch errors like + /// using flags that aren't defined in the usage string. + Argv(String), + + /// The given argv parsed successfully, but it did not match any example + /// usage of the program. + /// + /// Regrettably, there is no descriptive message describing *why* the + /// given argv didn't match any of the usage strings. + NoMatch, + + /// This indicates a problem deserializing a successful argv match into a + /// deserializable value. + Deserialize(String), + + /// Parsing failed, and the program usage should be printed next to the + /// failure message. Typically this wraps `Argv` and `NoMatch` errors. + WithProgramUsage(Box, String), + + /// Decoding or parsing failed because the command line specified that the + /// help message should be printed. + Help, + + /// Decoding or parsing failed because the command line specified that the + /// version should be printed + /// + /// The version is included as a payload to this variant. + Version(String), +} + +impl Error { + /// Return whether this was a fatal error or not. + /// + /// Non-fatal errors include requests to print the help or version + /// information of a program, while fatal errors include those such as + /// failing to decode or parse. + pub fn fatal(&self) -> bool { + match *self { + Help | Version(..) => false, + Usage(..) | Argv(..) | NoMatch | Deserialize(..) => true, + WithProgramUsage(ref b, _) => b.fatal(), + } + } + + /// Print this error and immediately exit the program. + /// + /// If the error is non-fatal (e.g., `Help` or `Version`), then the + /// error is printed to stdout and the exit status will be `0`. Otherwise, + /// when the error is fatal, the error is printed to stderr and the + /// exit status will be `1`. + pub fn exit(&self) -> ! { + if self.fatal() { + werr!("{}\n", self); + ::std::process::exit(1) + } else { + let _ = writeln!(&mut io::stdout(), "{}", self); + ::std::process::exit(0) + } + } +} + +type Result = result::Result; + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + WithProgramUsage(ref other, ref usage) => { + let other = other.to_string(); + if other.is_empty() { + write!(f, "{}", usage) + } else { + write!(f, "{}\n\n{}", other, usage) + } + } + Help => write!(f, ""), + NoMatch => write!(f, "Invalid arguments."), + Usage(ref s) | + Argv(ref s) | + Deserialize(ref s) | + Version(ref s) => write!(f, "{}", s), + } + } +} + +impl StdError for Error { + fn description(&self) -> &str { + match *self { + Usage(..) => "invalid usage string", + Argv(..) => "failed to parse specified argv", + NoMatch => "could not match specified argv", + Deserialize(..) => "failed to deserialize", + WithProgramUsage(..) => "failed to parse specified argv", + Help => "help message requested", + Version(..) => "version message requested", + } + } + + fn cause(&self) -> Option<&StdError> { + match *self { + WithProgramUsage(ref cause, _) => Some(&**cause), + _ => None, + } + } +} + +impl de::Error for Error { + fn custom(msg: T) -> Self { + Error::Deserialize(msg.to_string()) + } +} + +/// The main Docopt type, which is constructed with a Docopt usage string. +/// +/// This can be used to match command line arguments to produce a `ArgvMap`. +#[derive(Clone, Debug)] +pub struct Docopt { + p: Parser, + argv: Option>, + options_first: bool, + help: bool, + version: Option, +} + +impl Docopt { + /// Parse the Docopt usage string given. + /// + /// The `Docopt` value returned may be used immediately to parse command + /// line arguments with a default configuration. + /// + /// If there was a problem parsing the usage string, a `Usage` error + /// is returned. + pub fn new(usage: S) -> Result + where S: ::std::ops::Deref { + Parser::new(usage.deref()) + .map_err(Usage) + .map(|p| Docopt { + p: p, + argv: None, + options_first: false, + help: true, + version: None, + }) + } + + /// Parse and deserialize the given argv. + /// + /// This is a convenience method for + /// `parse().and_then(|vals| vals.deserialize())`. + /// + /// For details on how decoding works, please see the documentation for + /// `ArgvMap`. + pub fn deserialize<'a, 'de: 'a, D>(&'a self) -> Result + where D: de::Deserialize<'de> + { + self.parse().and_then(|vals| vals.deserialize()) + } + + /// Parse command line arguments and try to match them against a usage + /// pattern specified in the Docopt string. + /// + /// If there is a match, then an `ArgvMap` is returned, which maps + /// flags, commands and arguments to values. + /// + /// If parsing the command line arguments fails, then an `Argv` error is + /// returned. If parsing succeeds but there is no match, then a `NoMatch` + /// error is returned. Both of these errors are always returned inside a + /// `WithProgramUsage` error. + /// + /// If special handling of `help` or `version` is enabled (the former is + /// enabled by default), then `Help` or `Version` errors are returned + /// if `--help` or `--version` is present. + pub fn parse(&self) -> Result { + let argv = self.argv.clone().unwrap_or_else(Docopt::get_argv); + let vals = + self.p.parse_argv(argv, self.options_first) + .map_err(|s| self.err_with_usage(Argv(s))) + .and_then(|argv| + match self.p.matches(&argv) { + Some(m) => Ok(ArgvMap { map: m }), + None => Err(self.err_with_usage(NoMatch)), + })?; + if self.help && vals.get_bool("--help") { + return Err(self.err_with_full_doc(Help)); + } + match self.version { + Some(ref v) if vals.get_bool("--version") => { + return Err(Version(v.clone())) + } + _ => {}, + } + Ok(vals) + } + + /// Set the argv to be used for Docopt parsing. + /// + /// By default, when no argv is set, and it is automatically taken from + /// `std::env::args()`. + /// + /// The `argv` given *must* be the full set of `argv` passed to the + /// program. e.g., `["cp", "src", "dest"]` is right while `["src", "dest"]` + /// is wrong. + pub fn argv(mut self, argv: I) -> Docopt + where I: IntoIterator, S: AsRef { + self.argv = Some( + argv.into_iter().skip(1).map(|s| s.as_ref().to_owned()).collect() + ); + self + } + + /// Enables the "options first" Docopt behavior. + /// + /// The options first behavior means that all flags *must* appear before + /// position arguments. That is, after the first position argument is + /// seen, all proceeding arguments are interpreted as positional + /// arguments unconditionally. + pub fn options_first(mut self, yes: bool) -> Docopt { + self.options_first = yes; + self + } + + /// Enables automatic handling of `--help`. + /// + /// When this is enabled and `--help` appears anywhere in the arguments, + /// then a `Help` error will be returned. You may then use the `exit` + /// method on the error value to conveniently quit the program (which will + /// print the full usage string to stdout). + /// + /// Note that for this to work, `--help` must be a valid pattern. + /// + /// When disabled, there is no special handling of `--help`. + pub fn help(mut self, yes: bool) -> Docopt { + self.help = yes; + self + } + + /// Enables automatic handling of `--version`. + /// + /// When this is enabled and `--version` appears anywhere in the arguments, + /// then a `Version(s)` error will be returned, where `s` is the string + /// given here. You may then use the `exit` method on the error value to + /// convenient quit the program (which will print the version to stdout). + /// + /// When disabled (a `None` value), there is no special handling of + /// `--version`. + pub fn version(mut self, version: Option) -> Docopt { + self.version = version; + self + } + + #[doc(hidden)] + // Exposed for use in `docopt_macros`. + pub fn parser(&self) -> &Parser { + &self.p + } + + fn err_with_usage(&self, e: Error) -> Error { + WithProgramUsage( + Box::new(e), self.p.usage.trim().into()) + } + + fn err_with_full_doc(&self, e: Error) -> Error { + WithProgramUsage( + Box::new(e), self.p.full_doc.trim().into()) + } + + fn get_argv() -> Vec { + // Hmm, we should probably handle a Unicode decode error here... ---AG + ::std::env::args().skip(1).collect() + } +} + +/// A map containing matched values from command line arguments. +/// +/// The keys are just as specified in Docopt: `--flag` for a long flag or +/// `-f` for a short flag. (If `-f` is a synonym for `--flag`, then either +/// key will work.) `ARG` or `` specify a positional argument and `cmd` +/// specifies a command. +#[derive(Clone)] +pub struct ArgvMap { + #[doc(hidden)] + pub map: SynonymMap, +} + +impl ArgvMap { + /// Tries to deserialize the map of values into a struct. + /// + /// This method should always be called to deserialize a `ArgvMap` into + /// a struct. All fields of the struct must map to a corresponding key + /// in the `ArgvMap`. To this end, each member must have a special prefix + /// corresponding to the different kinds of patterns in Docopt. There are + /// three prefixes: `flag_`, `arg_` and `cmd_` which respectively + /// correspond to short/long flags, positional arguments and commands. + /// + /// If a Docopt item has a `-` in its name, then it is converted to an `_`. + /// + /// # Example + /// + /// ```rust + /// # extern crate docopt; + /// #[macro_use] + /// extern crate serde_derive; + /// # extern crate serde; + /// # fn main() { + /// use docopt::Docopt; + /// + /// const USAGE: &'static str = " + /// Usage: cargo [options] (build | test) + /// cargo --help + /// + /// Options: -v, --verbose + /// -h, --help + /// "; + /// + /// #[derive(Deserialize)] + /// struct Args { + /// cmd_build: bool, + /// cmd_test: bool, + /// flag_verbose: bool, + /// flag_h: bool, + /// } + /// + /// let argv = || vec!["cargo", "build", "-v"].into_iter(); + /// let args: Args = Docopt::new(USAGE) + /// .and_then(|d| d.argv(argv()).deserialize()) + /// .unwrap_or_else(|e| e.exit()); + /// assert!(args.cmd_build && !args.cmd_test + /// && args.flag_verbose && !args.flag_h); + /// # } + /// ``` + /// + /// Note that in the above example, `flag_h` is used but `flag_help` + /// could also be used. (In fact, both could be used at the same time.) + /// + /// In this example, only the `bool` type was used, but any type satisfying + /// the `Deserialize` trait is valid. + pub fn deserialize<'de, T: de::Deserialize<'de>>(self) -> Result { + de::Deserialize::deserialize(&mut Deserializer { + vals: self, + stack: vec![], + }) + } + + /// Finds the value corresponding to `key` and calls `as_bool()` on it. + /// If the key does not exist, `false` is returned. + pub fn get_bool(&self, key: &str) -> bool { + self.find(key).map_or(false, |v| v.as_bool()) + } + + /// Finds the value corresponding to `key` and calls `as_count()` on it. + /// If the key does not exist, `0` is returned. + pub fn get_count(&self, key: &str) -> u64 { + self.find(key).map_or(0, |v| v.as_count()) + } + + /// Finds the value corresponding to `key` and calls `as_str()` on it. + /// If the key does not exist, `""` is returned. + pub fn get_str(&self, key: &str) -> &str { + self.find(key).map_or("", |v| v.as_str()) + } + + /// Finds the value corresponding to `key` and calls `as_vec()` on it. + /// If the key does not exist, `vec!()` is returned. + pub fn get_vec(&self, key: &str) -> Vec<&str> { + self.find(key).map(|v| v.as_vec()).unwrap_or(vec!()) + } + + /// Return the raw value corresponding to some `key`. + /// + /// `key` should be a string in the traditional Docopt format. e.g., + /// `` or `--flag`. + pub fn find(&self, key: &str) -> Option<&Value> { + self.map.find(&key.into()) + } + + /// Return the number of values, not including synonyms. + pub fn len(&self) -> usize { + self.map.len() + } + + /// Converts a Docopt key to a struct field name. + /// This makes a half-hearted attempt at making the key a valid struct + /// field name (like replacing `-` with `_`), but it does not otherwise + /// guarantee that the result is a valid struct field name. + #[doc(hidden)] + pub fn key_to_struct_field(name: &str) -> String { + lazy_static! { + static ref RE: Regex = regex!( + r"^(?:--?(?P\S+)|(?:(?P\p{Lu}+)|<(?P[^>]+)>)|(?P\S+))$" + ); + } + fn sanitize(name: &str) -> String { + name.replace("-", "_") + } + + RE.replace(name, |cap: &Captures| { + let (flag, cmd) = ( + cap_or_empty(cap, "flag"), + cap_or_empty(cap, "cmd"), + ); + let (argu, argb) = ( + cap_or_empty(cap, "argu"), + cap_or_empty(cap, "argb"), + ); + let (prefix, name) = + if !flag.is_empty() { + ("flag_", flag) + } else if !argu.is_empty() { + ("arg_", argu) + } else if !argb.is_empty() { + ("arg_", argb) + } else if !cmd.is_empty() { + ("cmd_", cmd) + } else { + panic!("Unknown ArgvMap key: '{}'", name) + }; + let mut prefix = prefix.to_owned(); + prefix.push_str(&sanitize(name)); + prefix + }).into_owned() + } + + /// Converts a struct field name to a Docopt key. + #[doc(hidden)] + pub fn struct_field_to_key(field: &str) -> String { + lazy_static! { + static ref FLAG: Regex = regex!(r"^flag_"); + static ref ARG: Regex = regex!(r"^arg_"); + static ref LETTERS: Regex = regex!(r"^\p{Lu}+$"); + static ref CMD: Regex = regex!(r"^cmd_"); + } + fn desanitize(name: &str) -> String { + name.replace("_", "-") + } + let name = + if field.starts_with("flag_") { + let name = FLAG.replace(field, ""); + let mut pre_name = (if name.len() == 1 { "-" } else { "--" }) + .to_owned(); + pre_name.push_str(&*name); + pre_name + } else if field.starts_with("arg_") { + let name = ARG.replace(field, "").into_owned(); + if LETTERS.is_match(&name) { + name + } else { + let mut pre_name = "<".to_owned(); + pre_name.push_str(&*name); + pre_name.push('>'); + pre_name + } + } else if field.starts_with("cmd_") { + CMD.replace(field, "").into_owned() + } else { + panic!("Unrecognized struct field: '{}'", field) + }; + desanitize(&*name) + } +} + +impl fmt::Debug for ArgvMap { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.len() == 0 { + return write!(f, "{{EMPTY}}"); + } + + // This is a little crazy, but we want to group synonyms with + // their keys and sort them for predictable output. + let reverse: HashMap<&String, &String> = + self.map.synonyms().map(|(from, to)| (to, from)).collect(); + let mut keys: Vec<&String> = self.map.keys().collect(); + keys.sort(); + let mut first = true; + for &k in &keys { + if !first { write!(f, "\n")?; } else { first = false; } + match reverse.get(&k) { + None => { + write!(f, "{} => {:?}", k, self.map.get(k))? + } + Some(s) => { + write!(f, "{}, {} => {:?}", s, k, self.map.get(k))? + } + } + } + Ok(()) + } +} + +/// A matched command line value. +/// +/// The value can be a boolean, counted repetition, a plain string or a list +/// of strings. +/// +/// The various `as_{bool,count,str,vec}` methods provide convenient access +/// to values without destructuring manually. +#[derive(Clone, Debug, PartialEq)] +pub enum Value { + /// A boolean value from a flag that has no argument. + /// + /// The presence of a flag means `true` and the absence of a flag + /// means `false`. + Switch(bool), + + /// The number of occurrences of a repeated flag. + Counted(u64), + + /// A positional or flag argument. + /// + /// This is `None` when the positional argument or flag is not present. + /// Note that it is possible to have `Some("")` for a present but empty + /// argument. + Plain(Option), + + /// A List of positional or flag arguments. + /// + /// This list may be empty when no arguments or flags are present. + List(Vec), +} + +impl Value { + /// Returns the value as a bool. + /// + /// Counted repetitions are `false` if `0` and `true` otherwise. + /// Plain strings are `true` if present and `false` otherwise. + /// Lists are `true` if non-empty and `false` otherwise. + pub fn as_bool(&self) -> bool { + match *self { + Switch(b) => b, + Counted(n) => n > 0, + Plain(None) => false, + Plain(Some(_)) => true, + List(ref vs) => !vs.is_empty(), + } + } + + /// Returns the value as a count of the number of times it occurred. + /// + /// Booleans are `1` if `true` and `0` otherwise. + /// Plain strings are `1` if present and `0` otherwise. + /// Lists correspond to its length. + pub fn as_count(&self) -> u64 { + match *self { + Switch(b) => if b { 1 } else { 0 }, + Counted(n) => n, + Plain(None) => 0, + Plain(Some(_)) => 1, + List(ref vs) => vs.len() as u64, + } + } + + /// Returns the value as a string. + /// + /// All values return an empty string except for a non-empty plain string. + pub fn as_str(&self) -> &str { + match *self { + Switch(_) | Counted(_) | Plain(None) | List(_) => "", + Plain(Some(ref s)) => &**s, + } + } + + /// Returns the value as a list of strings. + /// + /// Booleans, repetitions and empty strings correspond to an empty list. + /// Plain strings correspond to a list of length `1`. + pub fn as_vec(&self) -> Vec<&str> { + match *self { + Switch(_) | Counted(_) | Plain(None) => vec![], + Plain(Some(ref s)) => vec![&**s], + List(ref vs) => vs.iter().map(|s| &**s).collect(), + } + } +} + +/// Deserializer for `ArgvMap` into your own `Deserialize`able types. +/// +/// In general, you shouldn't have to use this type directly. It is exposed +/// in case you want to write a generic function that produces a deserializable +/// value. For example, here's a function that takes a usage string, an argv +/// and produces a deserializable value: +/// +/// ```rust +/// # extern crate docopt; +/// extern crate serde; +/// # fn main() { +/// use docopt::Docopt; +/// use serde::de::Deserialize; +/// +/// fn deserialize<'de, D: Deserialize<'de>>(usage: &str, argv: &[&str]) +/// -> Result { +/// Docopt::new(usage) +/// .and_then(|d| d.argv(argv.iter()).deserialize()) +/// } +/// # } +pub struct Deserializer<'de> { + vals: ArgvMap, + stack: Vec>, +} + +#[derive(Debug)] +struct DeserializerItem<'de> { + key: String, + struct_field: &'de str, + val: Option, +} + +macro_rules! derr( + ($($arg:tt)*) => (return Err(Deserialize(format!($($arg)*)))) +); + +impl<'de> Deserializer<'de> { + fn push(&mut self, struct_field: &'de str) { + let key = ArgvMap::struct_field_to_key(struct_field); + self.stack + .push(DeserializerItem { + key: key.clone(), + struct_field: struct_field, + val: self.vals.find(&*key).cloned(), + }); + } + + fn pop(&mut self) -> Result { + match self.stack.pop() { + None => derr!("Could not deserialize value into unknown key."), + Some(it) => Ok(it), + } + } + + fn pop_key_val(&mut self) -> Result<(String, Value)> { + let it = self.pop()?; + match it.val { + None => { + derr!("Could not find argument '{}' (from struct field '{}'). +Note that each struct field must have the right key prefix, which must +be one of `cmd_`, `flag_` or `arg_`.", + it.key, + it.struct_field) + } + Some(v) => Ok((it.key, v)), + } + } + + fn pop_val(&mut self) -> Result { + let (_, v) = self.pop_key_val()?; + Ok(v) + } + + fn to_number(&mut self, expect: &str) -> Result + where T: FromStr + ToString, + ::Err: Debug + { + let (k, v) = self.pop_key_val()?; + match v { + Counted(n) => Ok(n.to_string().parse().unwrap()), // lol + _ => { + if v.as_str().trim().is_empty() { + Ok("0".parse().unwrap()) // lol + } else { + match v.as_str().parse() { + Err(_) => { + derr!("Could not deserialize '{}' to {} for '{}'.", + v.as_str(), + expect, + k) + } + Ok(v) => Ok(v), + } + } + } + } + } + + fn to_float(&mut self, expect: &str) -> Result { + let (k, v) = self.pop_key_val()?; + match v { + Counted(n) => Ok(n as f64), + _ => { + match v.as_str().parse() { + Err(_) => { + derr!("Could not deserialize '{}' to {} for '{}'.", + v.as_str(), + expect, + k) + } + Ok(v) => Ok(v), + } + } + } + } +} + +macro_rules! deserialize_num { + ($name:ident, $method:ident, $ty:ty) => ( + fn $name(self, visitor: V) -> Result + where V: de::Visitor<'de> + { + visitor.$method(self.to_number::<$ty>(stringify!($ty)).map(|n| n as $ty)?) + } + ); +} + +impl<'a, 'de> ::serde::Deserializer<'de> for &'a mut Deserializer<'de> { + type Error = Error; + + fn deserialize_any(self, _visitor: V) -> Result + where V: de::Visitor<'de> + { + unimplemented!() + } + + fn deserialize_bool(self, visitor: V) -> Result + where V: de::Visitor<'de> + { + visitor.visit_bool(self.pop_val().map(|v| v.as_bool())?) + } + + // wish for stable macro concat_idents! + deserialize_num!(deserialize_i8, visit_i8, i8); + deserialize_num!(deserialize_i16, visit_i16, i16); + deserialize_num!(deserialize_i32, visit_i32, i32); + deserialize_num!(deserialize_i64, visit_i64, i64); + deserialize_num!(deserialize_u8, visit_u8, u8); + deserialize_num!(deserialize_u16, visit_u16, u16); + deserialize_num!(deserialize_u32, visit_u32, u32); + deserialize_num!(deserialize_u64, visit_u64, u64); + + fn deserialize_f32(self, visitor: V) -> Result + where V: de::Visitor<'de> + { + visitor.visit_f32(self.to_float("f32").map(|n| n as f32)?) + } + + fn deserialize_f64(self, visitor: V) -> Result + where V: de::Visitor<'de> + { + visitor.visit_f64(self.to_float("f64")?) + } + + fn deserialize_char(self, visitor: V) -> Result + where V: de::Visitor<'de> + { + let (k, v) = self.pop_key_val()?; + let vstr = v.as_str(); + match vstr.chars().count() { + 1 => visitor.visit_char(vstr.chars().next().unwrap()), + _ => derr!("Could not deserialize '{}' into char for '{}'.", vstr, k), + } + } + + fn deserialize_str(self, visitor: V) -> Result + where V: de::Visitor<'de> + { + let s = self.pop_val()?; + visitor.visit_str(s.as_str()) + } + + fn deserialize_string(self, visitor:V) -> Result + where V: de::Visitor<'de> + { + self.deserialize_str(visitor) + } + + fn deserialize_bytes(self, _visitor: V) -> Result + where V: de::Visitor<'de> + { + unimplemented!() + } + + fn deserialize_byte_buf(self, _visitor: V) -> Result + where V: de::Visitor<'de> + { + unimplemented!() + } + + fn deserialize_option(self, visitor: V) -> Result + where V: de::Visitor<'de> + { + let is_some = match self.stack.last() { + None => derr!("Could not deserialize value into unknown key."), + Some(it) => it.val.as_ref().map_or(false, |v| v.as_bool()), + }; + if is_some { + visitor.visit_some(self) + } else { + visitor.visit_none() + } + } + + fn deserialize_unit(self, _visitor: V) -> Result + where V: de::Visitor<'de> + { + // I don't know what the right thing is here, so just fail for now. + panic!("I don't know how to read into a nil value.") + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result + where V: de::Visitor<'de> + { + visitor.visit_unit() + } + + fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result + where V: de::Visitor<'de> + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_tuple(self, _len: usize, _visitor: V) -> Result + where V: de::Visitor<'de> + { + unimplemented!() + } + + fn deserialize_tuple_struct(self, + _name: &'static str, + _len: usize, + _visitor: V) + -> Result + where V: de::Visitor<'de> + { + unimplemented!() + } + + fn deserialize_map(self, _visitor: V) -> Result + where V: de::Visitor<'de> + { + unimplemented!() + } + + fn deserialize_seq(mut self, visitor: V) -> Result + where V: de::Visitor<'de> + { + let (key, struct_field, val) = match self.stack.pop() { + None => derr!("Could not deserialize value into unknown key."), + Some(DeserializerItem {key, struct_field, val}) => (key, struct_field, val), + }; + let list = val.unwrap_or(List(vec![])); + let vals = list.as_vec(); + for val in vals.iter().rev() { + self.stack + .push(DeserializerItem { + key: key.clone(), + struct_field: struct_field, + val: Some(Plain(Some((*val).into()))), + }); + } + visitor.visit_seq(SeqDeserializer::new(&mut self, vals.len())) + } + + fn deserialize_struct(mut self, + _: &str, + fields: &'static [&'static str], + visitor: V) + -> Result + where V: de::Visitor<'de> + { + visitor.visit_seq(StructDeserializer::new(&mut self, fields)) + } + + fn deserialize_enum(self, _name: &str, variants: &[&str], visitor: V) -> Result + where V: de::Visitor<'de> + { + let v = self.pop_val()?.as_str().to_lowercase(); + let s = match variants.iter().find(|&n| n.to_lowercase() == v) { + Some(s) => s, + None => { + derr!("Could not match '{}' with any of \ + the allowed variants: {:?}", + v, + variants) + } + }; + visitor.visit_enum(s.into_deserializer()) + } + + fn deserialize_identifier(self, visitor: V) -> Result + where V: de::Visitor<'de> + { + self.deserialize_str(visitor) + } + + fn deserialize_ignored_any(self, visitor: V) -> Result + where V: de::Visitor<'de> + { + self.deserialize_any(visitor) + } +} + +struct SeqDeserializer<'a, 'de: 'a> { + de: &'a mut Deserializer<'de>, + len: usize, +} + +impl<'a, 'de> SeqDeserializer<'a, 'de> { + fn new(de: &'a mut Deserializer<'de>, len: usize) -> Self { + SeqDeserializer { de: de, len: len } + } +} + +impl<'a, 'de> de::SeqAccess<'de> for SeqDeserializer<'a, 'de> { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result> + where T: de::DeserializeSeed<'de> + { + if self.len == 0 { + return Ok(None); + } + self.len -= 1; + seed.deserialize(&mut *self.de).map(Some) + } + + fn size_hint(&self) -> Option { + return Some(self.len); + } +} + +struct StructDeserializer<'a, 'de: 'a> { + de: &'a mut Deserializer<'de>, + fields: &'static [&'static str], +} + +impl<'a, 'de> StructDeserializer<'a, 'de> { + fn new(de: &'a mut Deserializer<'de>, fields: &'static [&'static str]) -> Self { + StructDeserializer { + de: de, + fields: fields, + } + } +} + +impl<'a, 'de> de::SeqAccess<'de> for StructDeserializer<'a, 'de> { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result> + where T: de::DeserializeSeed<'de> + { + if self.fields.len() == 0 { + return Ok(None); + } + self.de.push(self.fields[0]); + self.fields = &self.fields[1..]; + seed.deserialize(&mut *self.de).map(Some) + } + + fn size_hint(&self) -> Option { + return Some(self.fields.len()); + } +} diff --git a/docopt-0.8.3/src/lib.rs b/docopt-0.8.3/src/lib.rs new file mode 100644 index 000000000..c7ae8d123 --- /dev/null +++ b/docopt-0.8.3/src/lib.rs @@ -0,0 +1,269 @@ +//! Docopt for Rust. This implementation conforms to the +//! [official description of Docopt](http://docopt.org/) and +//! [passes its test suite](https://github.com/docopt/docopt/pull/201). +//! +//! This library is [on GitHub](https://github.com/docopt/docopt.rs). +//! +//! Fundamentally, Docopt is a command line argument parser. The detail that +//! distinguishes it from most parsers is that the parser is derived from the +//! usage string. Here's a simple example: +//! +//! ```rust +//! use docopt::Docopt; +//! +//! // Write the Docopt usage string. +//! const USAGE: &'static str = " +//! Usage: cp [-a] +//! cp [-a] ... +//! +//! Options: +//! -a, --archive Copy everything. +//! "; +//! +//! // The argv. Normally you'd just use `parse` which will automatically +//! // use `std::env::args()`. +//! let argv = || vec!["cp", "-a", "file1", "file2", "dest/"]; +//! +//! // Parse argv and exit the program with an error message if it fails. +//! let args = Docopt::new(USAGE) +//! .and_then(|d| d.argv(argv().into_iter()).parse()) +//! .unwrap_or_else(|e| e.exit()); +//! +//! // Now access your argv values. Synonyms work just fine! +//! assert!(args.get_bool("-a") && args.get_bool("--archive")); +//! assert_eq!(args.get_vec(""), vec!["file1", "file2"]); +//! assert_eq!(args.get_str(""), "dest/"); +//! assert_eq!(args.get_str(""), ""); +//! ``` +//! +//! # Type based decoding +//! +//! Often, command line values aren't just strings or booleans---sometimes +//! they are integers, or enums, or something more elaborate. Using the +//! standard Docopt interface can be inconvenient for this purpose, because +//! you'll need to convert all of the values explicitly. Instead, this crate +//! provides a `Decoder` that converts an `ArgvMap` to your custom struct. +//! Here is the same example as above using type based decoding: +//! +//! ```rust +//! # extern crate docopt; +//! #[macro_use] +//! extern crate serde_derive; +//! # fn main() { +//! use docopt::Docopt; +//! +//! // Write the Docopt usage string. +//! const USAGE: &'static str = " +//! Usage: cp [-a] +//! cp [-a] ... +//! +//! Options: +//! -a, --archive Copy everything. +//! "; +//! +//! #[derive(Deserialize)] +//! struct Args { +//! arg_source: Vec, +//! arg_dest: String, +//! arg_dir: String, +//! flag_archive: bool, +//! } +//! +//! let argv = || vec!["cp", "-a", "file1", "file2", "dest/"]; +//! let args: Args = Docopt::new(USAGE) +//! .and_then(|d| d.argv(argv().into_iter()).deserialize()) +//! .unwrap_or_else(|e| e.exit()); +//! +//! // Now access your argv values. +//! fn s(x: &str) -> String { x.to_string() } +//! assert!(args.flag_archive); +//! assert_eq!(args.arg_source, vec![s("file1"), s("file2")]); +//! assert_eq!(args.arg_dir, s("dest/")); +//! assert_eq!(args.arg_dest, s("")); +//! # } +//! ``` +//! +//! # Command line arguments for `rustc` +//! +//! Here's an example with a subset of `rustc`'s command line arguments that +//! shows more of Docopt and some of the benefits of type based decoding. +//! +//! ```rust +//! # extern crate docopt; +//! #[macro_use] +//! extern crate serde_derive; +//! extern crate serde; +//! # fn main() { +//! # #![allow(non_snake_case)] +//! use docopt::Docopt; +//! use std::fmt; +//! +//! // Write the Docopt usage string. +//! const USAGE: &'static str = " +//! Usage: rustc [options] [--cfg SPEC... -L PATH...] INPUT +//! rustc (--help | --version) +//! +//! Options: +//! -h, --help Show this message. +//! --version Show the version of rustc. +//! --cfg SPEC Configure the compilation environment. +//! -L PATH Add a directory to the library search path. +//! --emit TYPE Configure the output that rustc will produce. +//! Valid values: asm, ir, bc, obj, link. +//! --opt-level LEVEL Optimize with possible levels 0-3. +//! "; +//! +//! #[derive(Deserialize)] +//! struct Args { +//! arg_INPUT: String, +//! flag_emit: Option, +//! flag_opt_level: Option, +//! flag_cfg: Vec, +//! flag_L: Vec, +//! flag_help: bool, +//! flag_version: bool, +//! } +//! +//! // This is easy. The decoder will automatically restrict values to +//! // strings that match one of the enum variants. +//! #[derive(Deserialize)] +//! # #[derive(Debug, PartialEq)] +//! enum Emit { Asm, Ir, Bc, Obj, Link } +//! +//! // This one is harder because we want the user to specify an integer, +//! // but restrict it to a specific range. So we implement `Deserialize` +//! // ourselves. +//! # #[derive(Debug, PartialEq)] +//! enum OptLevel { Zero, One, Two, Three } +//! struct OptLevelVisitor; +//! +//! impl<'de> serde::de::Visitor<'de> for OptLevelVisitor { +//! type Value = OptLevel; +//! +//! fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { +//! formatter.write_str("a number from range 0..3") +//! } +//! +//! fn visit_u8(self, n: u8) -> Result +//! where E: serde::de::Error +//! { +//! Ok(match n { +//! 0 => OptLevel::Zero, 1 => OptLevel::One, +//! 2 => OptLevel::Two, 3 => OptLevel::Three, +//! n => { +//! let err = format!( +//! "Could not deserialize '{}' as opt-level.", n); +//! return Err(E::custom(err)); +//! } +//! }) +//! } +//! } +//! +//! impl<'de> serde::de::Deserialize<'de> for OptLevel { +//! fn deserialize(d: D) -> Result +//! where D: serde::de::Deserializer<'de> +//! { +//! d.deserialize_u8(OptLevelVisitor) +//! } +//! } +//! +//! let argv = || vec!["rustc", "-L", ".", "-L", "..", "--cfg", "a", +//! "--opt-level", "2", "--emit=ir", "docopt.rs"]; +//! let args: Args = Docopt::new(USAGE) +//! .and_then(|d| d.argv(argv().into_iter()).deserialize()) +//! .unwrap_or_else(|e| e.exit()); +//! +//! // Now access your argv values. +//! fn s(x: &str) -> String { x.to_string() } +//! assert_eq!(args.arg_INPUT, "docopt.rs".to_string()); +//! assert_eq!(args.flag_L, vec![s("."), s("..")]); +//! assert_eq!(args.flag_cfg, vec![s("a")]); +//! assert_eq!(args.flag_opt_level, Some(OptLevel::Two)); +//! assert_eq!(args.flag_emit, Some(Emit::Ir)); +//! # } +//! ``` +//! +//! # The `docopt!` macro +//! +//! This package comes bundled with an additional crate, `docopt_macros`, +//! which provides a `docopt!` syntax extension. Its purpose is to automate +//! the creation of a Rust struct from a Docopt usage string. In particular, +//! this provides a single point of truth about the definition of command line +//! arguments in your program. +//! +//! Another advantage of using the macro is that errors in your Docopt usage +//! string will be caught at compile time. Stated differently, your program +//! will not compile with an invalid Docopt usage string. +//! +//! The example above using type based decoding can be simplified to this: +//! +//! ```ignore +//! #![feature(plugin)] +//! #![plugin(docopt_macros)] +//! +//! extern crate serde; +//! +//! extern crate docopt; +//! +//! // Write the Docopt usage string with the `docopt!` macro. +//! docopt!(Args, " +//! Usage: cp [-a] +//! cp [-a] ... +//! +//! Options: +//! -a, --archive Copy everything. +//! ") +//! +//! fn main() { +//! let argv = || vec!["cp", "-a", "file1", "file2", "dest/"]; +//! +//! // Your `Args` struct has a single static method defined on it, +//! // `docopt`, which will return a normal `Docopt` value. +//! let args: Args = Args::docopt().deserialize().unwrap_or_else(|e| e.exit()); +//! +//! // Now access your argv values. +//! fn s(x: &str) -> String { x.to_string() } +//! assert!(args.flag_archive); +//! assert_eq!(args.arg_source, vec![s("file1"), s("file2")]); +//! assert_eq!(args.arg_dir, s("dest/")); +//! assert_eq!(args.arg_dest, s("")); +//! } +//! ``` + +#![crate_name = "docopt"] +#![doc(html_root_url = "http://burntsushi.net/rustdoc/docopt")] + +#![deny(missing_docs)] + +#[macro_use] +extern crate lazy_static; +extern crate regex; +extern crate strsim; +#[allow(unused_imports)] +#[macro_use] +extern crate serde_derive; +extern crate serde; + +pub use dopt::{ArgvMap, Deserializer, Docopt, Error, Value}; + +macro_rules! werr( + ($($arg:tt)*) => ({ + use std::io::{Write, stderr}; + write!(&mut stderr(), $($arg)*).unwrap(); + }) +); + +macro_rules! regex( + ($s:expr) => (::regex::Regex::new($s).unwrap()); +); + +fn cap_or_empty<'t>(caps: ®ex::Captures<'t>, name: &str) -> &'t str { + caps.name(name).map_or("", |m| m.as_str()) +} + +mod dopt; +#[doc(hidden)] +pub mod parse; +mod synonym; +#[cfg(test)] +mod test; diff --git a/docopt-0.8.3/src/parse.rs b/docopt-0.8.3/src/parse.rs new file mode 100644 index 000000000..d3abcdf0e --- /dev/null +++ b/docopt-0.8.3/src/parse.rs @@ -0,0 +1,1488 @@ +// I am overall pretty displeased with the quality of code in this module. +// I wrote it while simultaneously trying to build a mental model of Docopt's +// specification (hint: one does not exist in written form). As a result, there +// is a lot of coupling and some duplication. +// +// Some things that I think are good about the following code: +// +// - The representation of a "usage pattern." I think it is a minimal +// representation of a pattern's syntax. (One possible tweak: +// `Optional>` -> `Optional>`.) +// - Some disciplined use of regexes. I use a pretty basic state machine +// for parsing patterns, but for teasing out the patterns and options +// from the Docopt string and for picking out flags with arguments, I +// think regexes aren't too bad. There may be one or two scary ones though. +// - The core matching algorithm is reasonably simple and concise, but I +// think writing down some contracts will help me figure out how to make +// the code clearer. +// +// Some bad things: +// +// - I tried several times to split some of the pieces in this module into +// separate modules. I could find no clear separation. This suggests that +// there is too much coupling between parsing components. I'm not convinced +// that the coupling is necessary. +// - The parsers for patterns and argv share some structure. There may be +// an easy abstraction waiting there. +// - It is not efficient in the slightest. I tried to be conservative with +// copying strings, but I think I failed. (It may not be worthwhile to fix +// this if it makes the code more awkward. Docopt does not need to be +// efficient.) +// +// Some things to do immediately: +// +// - Document representation and invariants. +// - Less important: write contracts for functions. +// +// Long term: +// +// - Write a specification for Docopt. + +pub use self::Argument::{Zero, One}; +pub use self::Atom::{Short, Long, Command, Positional}; +use self::Pattern::{Alternates, Sequence, Optional, Repeat, PatAtom}; + +use std::borrow::ToOwned; +use std::collections::{HashMap, HashSet}; +use std::collections::hash_map::Entry::{Vacant, Occupied}; +use std::cmp::Ordering; +use std::fmt; +use regex; +use regex::Regex; +use strsim::levenshtein; + +use dopt::Value::{self, Switch, Counted, Plain, List}; +use synonym::SynonymMap; +use cap_or_empty; + +macro_rules! err( + ($($arg:tt)*) => (return Err(format!($($arg)*))) +); + +#[derive(Clone)] +pub struct Parser { + pub program: String, + pub full_doc: String, + pub usage: String, + pub descs: SynonymMap, + usages: Vec, + last_atom_added: Option, // context for [default: ...] +} + +impl Parser { + pub fn new(doc: &str) -> Result { + let mut d = Parser { + program: String::new(), + full_doc: doc.into(), + usage: String::new(), + usages: vec!(), + descs: SynonymMap::new(), + last_atom_added: None, + }; + d.parse(doc)?; + Ok(d) + } + + pub fn matches(&self, argv: &Argv) -> Option> { + for usage in &self.usages { + match Matcher::matches(argv, usage) { + None => continue, + Some(vals) => return Some(vals), + } + } + None + } + + pub fn parse_argv(&self, argv: Vec, options_first: bool) + -> Result { + Argv::new(self, argv, options_first) + } +} + +impl Parser { + fn options_atoms(&self) -> Vec { + let mut atoms = vec!(); + for (atom, _) in self.descs.iter().filter(|&(_, opts)| opts.is_desc) { + atoms.push(atom.clone()); + } + atoms + } + + fn has_arg(&self, atom: &Atom) -> bool { + match self.descs.find(atom) { + None => false, + Some(opts) => opts.arg.has_arg(), + } + } + + fn has_repeat(&self, atom: &Atom) -> bool { + match self.descs.find(atom) { + None => false, + Some(opts) => opts.repeats, + } + } + + fn parse(&mut self, doc: &str) -> Result<(), String> { + lazy_static! { + static ref MUSAGE: Regex = Regex::new( + r"(?s)(?i:usage):\s*(?P\S+)(?P.*?)(?:$|\n\s*\n)" + ).unwrap(); + } + let caps = match MUSAGE.captures(doc) { + None => err!("Could not find usage patterns in doc string."), + Some(caps) => caps, + }; + if cap_or_empty(&caps, "prog").is_empty() { + err!("Could not find program name in doc string.") + } + self.program = cap_or_empty(&caps, "prog").to_string(); + self.usage = caps[0].to_string(); + + // Before we parse the usage patterns, we look for option descriptions. + // We do this because the information in option descriptions can be + // used to resolve ambiguities in usage patterns (i.e., whether + // `--flag ARG` is a flag with an argument or not). + // + // From the docopt page, "every" line starting with a `-` or a `--` + // is considered an option description. Instead, we restrict the lines + // to any line *not* in the usage pattern section. + // + // *sigh* Apparently the above is not true. The official test suite + // includes `Options: -a ...`, which means some lines not beginning + // with `-` can actually have options. + let (pstart, pend) = caps.get(0).map(|m|(m.start(), m.end())).unwrap(); + let (before, after) = (&doc[..pstart], &doc[pend..]); + // We process every line here (instead of restricting to lines starting + // with "-") because we need to check every line for a default value. + // The default value always belongs to the most recently defined desc. + for line in before.lines().chain(after.lines()) { + self.parse_desc(line)?; + } + + let mprog = format!( + "^(?:{})?\\s*(.*?)\\s*$", + regex::escape(cap_or_empty(&caps, "prog"))); + let pats = Regex::new(&*mprog).unwrap(); + + if cap_or_empty(&caps, "pats").is_empty() { + let pattern = PatParser::new(self, "").parse()?; + self.usages.push(pattern); + } else { + for line in cap_or_empty(&caps, "pats").lines() { + for pat in pats.captures_iter(line.trim()) { + let pattern = PatParser::new(self, &pat[1]).parse()?; + self.usages.push(pattern); + } + } + } + Ok(()) + } + + fn parse_desc(&mut self, full_desc: &str) -> Result<(), String> { + lazy_static! { + static ref OPTIONS: Regex = regex!(r"^\s*(?i:options:)\s*"); + static ref ISFLAG: Regex = regex!(r"^(-\S|--\S)"); + static ref REMOVE_DESC: Regex = regex!(r" .*$"); + static ref NORMALIZE_FLAGS: Regex = regex!(r"([^-\s]), -"); + static ref FIND_FLAGS: Regex = regex!(r"(?x) + (?:(?P--[^\x20\t=]+)|(?P-[^\x20\t=]+)) + (?:(?:\x20|=)(?P[^.-]\S*))? + (?P\x20\.\.\.)? + "); + } + let desc = OPTIONS.replace(full_desc.trim(), ""); + let desc = &*desc; + if !ISFLAG.is_match(desc) { + self.parse_default(full_desc)?; + return Ok(()) + } + + // Get rid of the description, which must be at least two spaces + // after the flag or argument. + let desc = REMOVE_DESC.replace(desc, ""); + // Normalize `-x, --xyz` to `-x --xyz`. + let desc = NORMALIZE_FLAGS.replace(&desc, "$1 -"); + let desc = desc.trim(); + + let (mut short, mut long) = <(String, String)>::default(); + let mut has_arg = false; + let mut last_end = 0; + let mut repeated = false; + for flags in FIND_FLAGS.captures_iter(desc) { + last_end = flags.get(0).unwrap().end(); + if !cap_or_empty(&flags, "repeated").is_empty() { + // If the "repeated" subcapture is not empty, then we have + // a valid repeated option. + repeated = true; + } + let (s, l) = ( + cap_or_empty(&flags, "short"), + cap_or_empty(&flags, "long"), + ); + if !s.is_empty() { + if !short.is_empty() { + err!("Only one short flag is allowed in an option \ + description, but found '{}' and '{}'.", short, s) + } + short = s.into() + } + if !l.is_empty() { + if !long.is_empty() { + err!("Only one long flag is allowed in an option \ + description, but found '{}' and '{}'.", long, l) + } + long = l.into() + } + if let Some(arg) = flags.name("arg").map(|m| m.as_str()) { + if !arg.is_empty() { + if !Atom::is_arg(arg) { + err!("Argument '{}' is not of the form ARG or .", + arg) + } + has_arg = true; // may be changed to default later + } + } + } + // Make sure that we consumed everything. If there are leftovers, + // then there is some malformed description. Alert the user. + assert!(last_end <= desc.len()); + if last_end < desc.len() { + err!("Extraneous text '{}' in option description '{}'.", + &desc[last_end..], desc) + } + self.add_desc(&short, &long, has_arg, repeated)?; + // Looking for default in this line must come after adding the + // description, otherwise `parse_default` won't know which option + // to assign it to. + self.parse_default(full_desc) + } + + fn parse_default(&mut self, desc: &str) -> Result<(), String> { + lazy_static! { + static ref FIND_DEFAULT: Regex = regex!( + r"\[(?i:default):(?P.*)\]" + ); + } + let defval = + match FIND_DEFAULT.captures(desc) { + None => return Ok(()), + Some(c) => cap_or_empty(&c, "val").trim(), + }; + let last_atom = + match self.last_atom_added { + None => err!("Found default value '{}' in '{}' before first \ + option description.", defval, desc), + Some(ref atom) => atom, + }; + let opts = + self.descs + .find_mut(last_atom) + .expect(&*format!("BUG: last opt desc key ('{:?}') is invalid.", + last_atom)); + match opts.arg { + One(None) => {}, // OK + Zero => + err!("Cannot assign default value '{}' to flag '{}' \ + that has no arguments.", defval, last_atom), + One(Some(ref curval)) => + err!("Flag '{}' already has a default value \ + of '{}' (second default value: '{}').", + last_atom, curval, defval), + } + opts.arg = One(Some(defval.into())); + Ok(()) + } + + fn add_desc( + &mut self, + short: &str, + long: &str, + has_arg: bool, + repeated: bool, + ) -> Result<(), String> { + assert!(!short.is_empty() || !long.is_empty()); + if !short.is_empty() && short.chars().count() != 2 { + // It looks like the reference implementation just ignores + // these lines. + return Ok(()); + } + let mut opts = Options::new( + repeated, if has_arg { One(None) } else { Zero }); + opts.is_desc = true; + + if !short.is_empty() && !long.is_empty() { + let (short, long) = (Atom::new(short), Atom::new(long)); + self.descs.insert(long.clone(), opts); + self.descs.insert_synonym(short, long.clone()); + self.last_atom_added = Some(long); + } else if !short.is_empty() { + let short = Atom::new(short); + self.descs.insert(short.clone(), opts); + self.last_atom_added = Some(short); + } else if !long.is_empty() { + let long = Atom::new(long); + self.descs.insert(long.clone(), opts); + self.last_atom_added = Some(long); + } + Ok(()) + } +} + +impl fmt::Debug for Parser { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn sorted(mut xs: Vec) -> Vec { + xs.sort(); xs + } + + writeln!(f, "=====")?; + writeln!(f, "Program: {}", self.program)?; + + writeln!(f, "Option descriptions:")?; + let keys = sorted(self.descs.keys().collect()); + for &k in &keys { + writeln!(f, " '{}' => {:?}", k, self.descs.get(k))?; + } + + writeln!(f, "Synonyms:")?; + let keys: Vec<(&Atom, &Atom)> = + sorted(self.descs.synonyms().collect()); + for &(from, to) in &keys { + writeln!(f, " {:?} => {:?}", from, to)?; + } + + writeln!(f, "Usages:")?; + for pat in &self.usages { + writeln!(f, " {:?}", pat)?; + } + writeln!(f, "=====") + } +} + +struct PatParser<'a> { + dopt: &'a mut Parser, + tokens: Vec, // used while parsing a single usage pattern + curi: usize, // ^^ index into pattern chars + expecting: Vec, // stack of expected ']' or ')' +} + +impl<'a> PatParser<'a> { + fn new(dopt: &'a mut Parser, pat: &str) -> PatParser<'a> { + PatParser { + dopt: dopt, + tokens: pattern_tokens(pat), + curi: 0, + expecting: vec!(), + } + } + + fn parse(&mut self) -> Result { + // let mut seen = HashSet::new(); + let mut p = self.pattern()?; + match self.expecting.pop() { + None => {}, + Some(c) => err!("Unclosed group. Expected '{}'.", c), + } + p.add_options_shortcut(self.dopt); + p.tag_repeats(&mut self.dopt.descs); + Ok(p) + } + + fn pattern(&mut self) -> Result { + let mut alts = vec!(); + let mut seq = vec!(); + while !self.is_eof() { + match self.cur() { + "..." => { + err!("'...' must appear directly after a group, argument, \ + flag or command.") + } + "-" | "--" => { + // As per specification, `-` and `--` by themselves are + // just commands that should be interpreted conventionally. + seq.push(self.command()?); + } + "|" => { + if seq.is_empty() { + err!("Unexpected '|'. Not in form 'a | b | c'.") + } + self.next_noeof("pattern")?; + alts.push(Sequence(seq)); + seq = vec!(); + } + "]" | ")" => { + if seq.is_empty() { + err!("Unexpected '{}'. Empty groups are not allowed.", + self.cur()) + } + match self.expecting.pop() { + None => err!("Unexpected '{}'. No open bracket found.", + self.cur()), + Some(c) => { + if c != self.cur().chars().next().unwrap() { + err!("Expected '{}' but got '{}'.", + c, self.cur()) + } + } + } + let mk: fn(Vec) -> Pattern = + if self.cur() == "]" { Optional } else { Sequence }; + self.next(); + return + if alts.is_empty() { + Ok(mk(seq)) + } else { + alts.push(Sequence(seq)); + Ok(mk(vec!(Alternates(alts)))) + } + } + "[" => { + // Check for special '[options]' shortcut. + if self.atis(1, "options") && self.atis(2, "]") { + self.next(); // cur == options + self.next(); // cur == ] + self.next(); + seq.push(self.maybe_repeat(Optional(vec!()))); + continue + } + self.expecting.push(']'); + seq.push(self.group()?); + } + "(" => { + self.expecting.push(')'); + seq.push(self.group()?); + } + _ => { + if Atom::is_short(self.cur()) { + seq.extend(self.flag_short()?.into_iter()); + } else if Atom::is_long(self.cur()) { + seq.push(self.flag_long()?); + } else if Atom::is_arg(self.cur()) { + // These are always positional. + // Arguments for -s and --short are picked up + // when parsing flags. + seq.push(self.positional()?); + } else if Atom::is_cmd(self.cur()) { + seq.push(self.command()?); + } else { + err!("Unknown token type '{}'.", self.cur()) + } + } + } + } + if alts.is_empty() { + Ok(Sequence(seq)) + } else { + alts.push(Sequence(seq)); + Ok(Alternates(alts)) + } + } + + fn flag_short(&mut self) -> Result, String> { + let mut seq = vec!(); + let stacked: String = self.cur()[1..].into(); + for (i, c) in stacked.chars().enumerate() { + let atom = self.dopt.descs.resolve(&Short(c)); + let mut pat = PatAtom(atom.clone()); + if self.dopt.has_repeat(&atom) { + pat = Pattern::repeat(pat); + } + seq.push(pat); + + // The only way for a short option to have an argument is if + // it's specified in an option description. + if !self.dopt.has_arg(&atom) { + self.add_atom_ifnotexists(Zero, &atom); + } else { + // At this point, the flag MUST have an argument. Therefore, + // we interpret the "rest" of the characters as the argument. + // If the "rest" is empty, then we peek to find and make sure + // there is an argument. + let rest = &stacked[i+1..]; + if rest.is_empty() { + self.next_flag_arg(&atom)?; + } else { + self.errif_invalid_flag_arg(&atom, rest)?; + } + // We either error'd or consumed the rest of the short stack as + // an argument. + break + } + } + self.next(); + // This is a little weird. We've got to manually look for a repeat + // operator right after the stack, and then apply it to each short + // flag we generated. + // If "sequences" never altered semantics, then we could just use that + // here to group a short stack. + if self.atis(0, "...") { + self.next(); + seq = seq.into_iter().map(Pattern::repeat).collect(); + } + Ok(seq) + } + + fn flag_long(&mut self) -> Result { + let (atom, arg) = parse_long_equal(self.cur())?; + let atom = self.dopt.descs.resolve(&atom); + if self.dopt.descs.contains_key(&atom) { + // Options already exist for this atom, so we must check to make + // sure things are consistent. + let has_arg = self.dopt.has_arg(&atom); + if arg.has_arg() && !has_arg { + // Found `=` in usage, but previous usage of this flag + // didn't specify an argument. + err!("Flag '{}' does not take any arguments.", atom) + } else if !arg.has_arg() && has_arg { + // Didn't find any `=` in usage for this flag, but previous + // usage of this flag specifies an argument. + // So look for `--flag ARG` + self.next_flag_arg(&atom)?; + // We don't care about the value of `arg` since options + // already exist. (In which case, the argument value can never + // change.) + } + } + self.add_atom_ifnotexists(arg, &atom); + self.next(); + let pat = if self.dopt.has_repeat(&atom) { + Pattern::repeat(PatAtom(atom)) + } else { + PatAtom(atom) + }; + Ok(self.maybe_repeat(pat)) + } + + fn next_flag_arg(&mut self, atom: &Atom) -> Result<(), String> { + self.next_noeof(&*format!("argument for flag '{}'", atom))?; + self.errif_invalid_flag_arg(atom, self.cur()) + } + + fn errif_invalid_flag_arg(&self, atom: &Atom, arg: &str) + -> Result<(), String> { + if !Atom::is_arg(arg) { + err!("Expected argument for flag '{}', but found \ + malformed argument '{}'.", atom, arg) + } + Ok(()) + } + + fn command(&mut self) -> Result { + let atom = Atom::new(self.cur()); + self.add_atom_ifnotexists(Zero, &atom); + self.next(); + Ok(self.maybe_repeat(PatAtom(atom))) + } + + fn positional(&mut self) -> Result { + let atom = Atom::new(self.cur()); + self.add_atom_ifnotexists(Zero, &atom); + self.next(); + Ok(self.maybe_repeat(PatAtom(atom))) + } + + fn add_atom_ifnotexists(&mut self, arg: Argument, atom: &Atom) { + if !self.dopt.descs.contains_key(atom) { + let opts = Options::new(false, arg); + self.dopt.descs.insert(atom.clone(), opts); + } + } + + fn group(&mut self) + -> Result { + self.next_noeof("pattern")?; + let pat = self.pattern()?; + Ok(self.maybe_repeat(pat)) + } + + fn maybe_repeat(&mut self, pat: Pattern) -> Pattern { + if self.atis(0, "...") { + self.next(); + Pattern::repeat(pat) + } else { + pat + } + } + + fn is_eof(&self) -> bool { + self.curi == self.tokens.len() + } + fn next(&mut self) { + if self.curi == self.tokens.len() { + return + } + self.curi += 1; + } + fn next_noeof(&mut self, expected: &str) -> Result<(), String> { + self.next(); + if self.curi == self.tokens.len() { + err!("Expected {} but reached end of usage pattern.", expected) + } + Ok(()) + } + fn cur(&self) -> &str { + &*self.tokens[self.curi] + } + fn atis(&self, offset: usize, is: &str) -> bool { + let i = self.curi + offset; + i < self.tokens.len() && self.tokens[i] == is + } +} + +#[derive(Clone, Debug)] +enum Pattern { + Alternates(Vec), + Sequence(Vec), + Optional(Vec), + Repeat(Box), + PatAtom(Atom), +} + +#[derive(PartialEq, Eq, Ord, Hash, Clone, Debug)] +pub enum Atom { + Short(char), + Long(String), + Command(String), + Positional(String), +} + +#[derive(Clone, Debug)] +pub struct Options { + /// Set to true if this atom is ever repeated in any context. + /// For positional arguments, non-argument flags and commands, repetition + /// means that they become countable. + /// For flags with arguments, repetition means multiple distinct values + /// can be specified (and are represented as a Vec). + pub repeats: bool, + + /// This specifies whether this atom has any arguments. + /// For commands and positional arguments, this is always Zero. + /// Flags can have zero or one argument, with an optionally default value. + pub arg: Argument, + + /// Whether it shows up in the "options description" second. + pub is_desc: bool, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum Argument { + Zero, + One(Option), // optional default value +} + +impl Pattern { + fn add_options_shortcut(&mut self, par: &Parser) { + fn add(pat: &mut Pattern, all_atoms: &HashSet, par: &Parser) { + match *pat { + Alternates(ref mut ps) | Sequence(ref mut ps) => { + for p in ps.iter_mut() { add(p, all_atoms, par) } + } + Repeat(ref mut p) => add(&mut **p, all_atoms, par), + PatAtom(_) => {} + Optional(ref mut ps) => { + if !ps.is_empty() { + for p in ps.iter_mut() { add(p, all_atoms, par) } + } else { + for atom in par.options_atoms().into_iter() { + if !all_atoms.contains(&atom) { + if par.has_repeat(&atom) { + ps.push(Pattern::repeat(PatAtom(atom))); + } else { + ps.push(PatAtom(atom)); + } + } + } + } + } + } + } + let all_atoms = self.all_atoms(); + add(self, &all_atoms, par); + } + + fn all_atoms(&self) -> HashSet { + fn all_atoms(pat: &Pattern, set: &mut HashSet) { + match *pat { + Alternates(ref ps) | Sequence(ref ps) | Optional(ref ps) => { + for p in ps.iter() { all_atoms(p, set) } + } + Repeat(ref p) => all_atoms(&**p, set), + PatAtom(ref a) => { set.insert(a.clone()); } + } + } + let mut set = HashSet::new(); + all_atoms(self, &mut set); + set + } + + fn tag_repeats(&self, map: &mut SynonymMap) { + fn dotag(p: &Pattern, + rep: bool, + map: &mut SynonymMap, + seen: &mut HashSet) { + match *p { + Alternates(ref ps) => { + // This is a bit tricky. Basically, we don't want the + // existence of an item in mutually exclusive alternations + // to affect whether it repeats or not. + // However, we still need to record seeing each item in + // each alternation. + let fresh = seen.clone(); + for p in ps.iter() { + let mut isolated = fresh.clone(); + dotag(p, rep, map, &mut isolated); + for a in isolated.into_iter() { + seen.insert(a); + } + } + } + Sequence(ref ps) => { + for p in ps.iter() { + dotag(p, rep, map, seen) + } + } + Optional(ref ps) => { + for p in ps.iter() { + dotag(p, rep, map, seen) + } + } + Repeat(ref p) => dotag(&**p, true, map, seen), + PatAtom(ref atom) => { + let opt = map.find_mut(atom).expect("bug: no atom found"); + opt.repeats = opt.repeats || rep || seen.contains(atom); + seen.insert(atom.clone()); + } + } + } + let mut seen = HashSet::new(); + dotag(self, false, map, &mut seen); + } + + fn repeat(p: Pattern) -> Pattern { + match p { + p @ Repeat(_) => p, + p => Repeat(Box::new(p)), + } + } +} + +impl Atom { + pub fn new(s: &str) -> Atom { + if Atom::is_short(s) { + Short(s[1..].chars().next().unwrap()) + } else if Atom::is_long(s) { + Long(s[2..].into()) + } else if Atom::is_arg(s) { + if s.starts_with("<") && s.ends_with(">") { + Positional(s[1..s.len()-1].into()) + } else { + Positional(s.into()) + } + } else if Atom::is_cmd(s) { + Command(s.into()) + } else { + panic!("Unknown atom string: '{}'", s) + } + } + + fn is_short(s: &str) -> bool { + lazy_static! { + static ref RE: Regex = regex!(r"^-[^-]\S*$"); + } + RE.is_match(s) + } + + fn is_long(s: &str) -> bool { + lazy_static! { + static ref RE: Regex = regex!(r"^--\S+(?:<[^>]+>)?$"); + } + RE.is_match(s) + } + + fn is_long_argv(s: &str) -> bool { + lazy_static! { + static ref RE: Regex = regex!(r"^--\S+(=.+)?$"); + } + RE.is_match(s) + } + + fn is_arg(s: &str) -> bool { + lazy_static! { + static ref RE: Regex = regex!(r"^(\p{Lu}+|<[^>]+>)$"); + } + RE.is_match(s) + } + + fn is_cmd(s: &str) -> bool { + lazy_static! { + static ref RE: Regex = regex!(r"^(-|--|[^-]\S*)$"); + } + RE.is_match(s) + } + + // Assigns an integer to each variant of Atom. (For easier sorting.) + fn type_as_usize(&self) -> usize { + match *self { + Short(_) => 0, + Long(_) => 1, + Command(_) => 2, + Positional(_) => 3, + } + } +} + +impl PartialOrd for Atom { + fn partial_cmp(&self, other: &Atom) -> Option { + match (self, other) { + (&Short(c1), &Short(c2)) => c1.partial_cmp(&c2), + (&Long(ref s1), &Long(ref s2)) => s1.partial_cmp(s2), + (&Command(ref s1), &Command(ref s2)) => s1.partial_cmp(s2), + (&Positional(ref s1), &Positional(ref s2)) => s1.partial_cmp(s2), + (a1, a2) => a1.type_as_usize().partial_cmp(&a2.type_as_usize()), + } + } +} + +impl fmt::Display for Atom { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Short(c) => write!(f, "-{}", c), + Long(ref s) => write!(f, "--{}", s), + Command(ref s) => write!(f, "{}", s), + Positional(ref s) => { + if s.chars().all(|c| c.is_uppercase()) { + write!(f, "{}", s) + } else { + write!(f, "<{}>", s) + } + } + } + } +} + + +impl Options { + fn new(rep: bool, arg: Argument) -> Options { + Options { repeats: rep, arg: arg, is_desc: false, } + } +} + +impl Argument { + fn has_arg(&self) -> bool { + match *self { + Zero => false, + One(_) => true, + } + } +} + +#[doc(hidden)] +pub struct Argv<'a> { + /// A representation of an argv string as an ordered list of tokens. + /// This contains only positional arguments and commands. + positional: Vec, + /// Same as positional, but contains short and long flags. + /// Each flag may have an argument string. + flags: Vec, + /// Counts the number of times each flag appears. + counts: HashMap, + + // State for parser. + dopt: &'a Parser, + argv: Vec, + curi: usize, + options_first: bool, +} + +#[derive(Clone, Debug)] +struct ArgvToken { + atom: Atom, + arg: Option, +} + +impl<'a> Argv<'a> { + fn new(dopt: &'a Parser, argv: Vec, options_first: bool) + -> Result, String> { + let mut a = Argv { + positional: vec!(), + flags: vec!(), + counts: HashMap::new(), + dopt: dopt, + argv: argv.iter().cloned().collect(), + curi: 0, + options_first: options_first, + }; + a.parse()?; + for flag in &a.flags { + match a.counts.entry(flag.atom.clone()) { + Vacant(v) => { v.insert(1); } + Occupied(mut v) => { *v.get_mut() += 1; } + } + } + Ok(a) + } + + fn parse(&mut self) -> Result<(), String> { + let mut seen_double_dash = false; + while self.curi < self.argv.len() { + let do_flags = + !seen_double_dash + && (!self.options_first || self.positional.is_empty()); + + if do_flags && Atom::is_short(self.cur()) { + let stacked: String = self.cur()[1..].into(); + for (i, c) in stacked.chars().enumerate() { + let mut tok = ArgvToken { + atom: self.dopt.descs.resolve(&Short(c)), + arg: None, + }; + if !self.dopt.descs.contains_key(&tok.atom) { + err!("Unknown flag: '{}'", &tok.atom); + } + if !self.dopt.has_arg(&tok.atom) { + self.flags.push(tok); + } else { + let rest = &stacked[i+1..]; + tok.arg = Some( + if rest.is_empty() { + let arg = self.next_arg(&tok.atom)?; + arg.into() + } else { + rest.into() + } + ); + self.flags.push(tok); + // We've either produced an error or gobbled up the + // rest of these stacked short flags, so stop. + break + } + } + } else if do_flags && Atom::is_long_argv(self.cur()) { + let (atom, mut arg) = parse_long_equal_argv(self.cur()); + let atom = self.dopt.descs.resolve(&atom); + if !self.dopt.descs.contains_key(&atom) { + return self.err_unknown_flag(&atom) + } + if arg.is_some() && !self.dopt.has_arg(&atom) { + err!("Flag '{}' cannot have an argument, but found '{}'.", + &atom, arg.as_ref().unwrap()) + } else if arg.is_none() && self.dopt.has_arg(&atom) { + self.next_noeof(&*format!("argument for flag '{}'", + &atom))?; + arg = Some(self.cur().into()); + } + self.flags.push(ArgvToken { atom: atom, arg: arg }); + } else { + if !seen_double_dash && self.cur() == "--" { + seen_double_dash = true; + } else { + // Yup, we *always* insert a positional argument, which + // means we completely neglect `Command` here. + // This is because we can't tell whether something is a + // `command` or not until we start pattern matching. + let tok = ArgvToken { + atom: Positional(self.cur().into()), + arg: None, + }; + self.positional.push(tok); + } + } + self.next() + } + Ok(()) + } + + fn err_unknown_flag(&self, atom: &Atom) -> Result<(), String> { + use std::usize::MAX; + let mut best = String::new(); + let flag = atom.to_string(); + let mut min = MAX; + + let mut possibles = Vec::new(); + + for (key, _) in self.dopt.descs.synonyms() { + possibles.push(key); + } + + for key in self.dopt.descs.keys() { + possibles.push(key); + } + + for key in &possibles { + match **key { + Long(_) | Command(_) => { + let name = key.to_string(); + let dist = levenshtein(&flag, &name); + if dist < 3 && dist < min { + min = dist; + best = name; + } + } + _ => {} + } + } + if best.is_empty() { + err!("Unknown flag: '{}'", &atom); + } else { + err!("Unknown flag: '{}'. Did you mean '{}'?", &atom, &best) + } + } + + fn cur(&self) -> &str { self.at(0) } + fn at(&self, i: usize) -> &str { + &*self.argv[self.curi + i] + } + fn next(&mut self) { + if self.curi < self.argv.len() { + self.curi += 1 + } + } + fn next_arg(&mut self, atom: &Atom) -> Result<&str, String> { + let expected = format!("argument for flag '{}'", atom); + self.next_noeof(&*expected)?; + Ok(self.cur()) + } + fn next_noeof(&mut self, expected: &str) -> Result<(), String> { + self.next(); + if self.curi == self.argv.len() { + err!("Expected {} but reached end of arguments.", expected) + } + Ok(()) + } +} + +impl<'a> fmt::Debug for Argv<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + writeln!(f, "Positional: {:?}", self.positional)?; + writeln!(f, "Flags: {:?}", self.flags)?; + writeln!(f, "Counts: {:?}", self.counts)?; + Ok(()) + } +} + +struct Matcher<'a, 'b:'a> { + argv: &'a Argv<'b>, +} + +#[derive(Clone, Debug, PartialEq)] +struct MState { + argvi: usize, // index into Argv.positional + counts: HashMap, // flags remaining for pattern consumption + max_counts: HashMap, // optional flag appearances + vals: HashMap, +} + +impl MState { + fn fill_value(&mut self, key: Atom, rep: bool, arg: Option) + -> bool { + match (arg, rep) { + (None, false) => { + self.vals.insert(key, Switch(true)); + } + (Some(arg), false) => { + self.vals.insert(key, Plain(Some(arg))); + } + (None, true) => { + match self.vals.entry(key) { + Vacant(v) => { v.insert(Counted(1)); } + Occupied(mut v) => { + match *v.get_mut() { + Counted(ref mut c) => { *c += 1; } + _ => return false, + } + } + } + } + (Some(arg), true) => { + match self.vals.entry(key) { + Vacant(v) => { v.insert(List(vec!(arg))); } + Occupied(mut v) => { + match *v.get_mut() { + List(ref mut vs) => vs.push(arg), + _ => return false, + } + } + } + } + } + true + } + + fn add_value(&mut self, opts: &Options, + spec: &Atom, atom: &Atom, arg: &Option) -> bool { + assert!(opts.arg.has_arg() == arg.is_some(), + "'{:?}' should have an argument but doesn't", atom); + match *atom { + Short(_) | Long(_) => { + self.fill_value(spec.clone(), opts.repeats, arg.clone()) + } + Positional(ref v) => { + assert!(!opts.arg.has_arg()); + self.fill_value(spec.clone(), opts.repeats, Some(v.clone())) + } + Command(_) => { + assert!(!opts.arg.has_arg()); + self.fill_value(spec.clone(), opts.repeats, None) + } + } + } + + fn use_flag(&mut self, flag: &Atom) -> bool { + match self.max_counts.entry(flag.clone()) { + Vacant(v) => { v.insert(0); } + Occupied(_) => {} + } + match self.counts.entry(flag.clone()) { + Vacant(_) => { false } + Occupied(mut v) => { + let c = v.get_mut(); + if *c == 0 { + false + } else { + *c -= 1; + true + } + } + } + } + + fn use_optional_flag(&mut self, flag: &Atom) { + match self.max_counts.entry(flag.clone()) { + Vacant(v) => { v.insert(1); } + Occupied(mut v) => { *v.get_mut() += 1; } + } + } + + fn match_cmd_or_posarg(&mut self, spec: &Atom, argv: &ArgvToken) + -> Option { + match (spec, &argv.atom) { + (_, &Command(_)) => { + // This is impossible because the argv parser doesn't know + // how to produce `Command` values. + unreachable!() + } + (&Command(ref n1), &Positional(ref n2)) if n1 == n2 => { + // Coerce a positional to a command because the pattern + // demands it and the positional argument matches it. + self.argvi += 1; + Some(ArgvToken { atom: spec.clone(), arg: None }) + } + (&Positional(_), _) => { + self.argvi += 1; + Some(argv.clone()) + } + _ => None, + } + } +} + +impl<'a, 'b> Matcher<'a, 'b> { + fn matches(argv: &'a Argv, pat: &Pattern) + -> Option> { + let m = Matcher { argv: argv }; + let init = MState { + argvi: 0, + counts: argv.counts.clone(), + max_counts: HashMap::new(), + vals: HashMap::new(), + }; + m.states(pat, &init) + .into_iter() + .filter(|s| m.state_consumed_all_argv(s)) + .filter(|s| m.state_has_valid_flags(s)) + .filter(|s| m.state_valid_num_flags(s)) + .collect::>() + .into_iter() + .next() + .map(|mut s| { + m.add_flag_values(&mut s); + m.add_default_values(&mut s); + + // Build a synonym map so that it's easier to look up values. + let mut synmap: SynonymMap = + s.vals.into_iter() + .map(|(k, v)| (k.to_string(), v)) + .collect(); + for (from, to) in argv.dopt.descs.synonyms() { + let (from, to) = (from.to_string(), to.to_string()); + if synmap.contains_key(&to) { + synmap.insert_synonym(from, to); + } + } + synmap + }) + } + + fn token_from(&self, state: &MState) -> Option<&ArgvToken> { + self.argv.positional.get(state.argvi) + } + + fn add_value(&self, state: &mut MState, + atom_spec: &Atom, atom: &Atom, arg: &Option) + -> bool { + let opts = self.argv.dopt.descs.get(atom_spec); + state.add_value(opts, atom_spec, atom, arg) + } + + fn add_flag_values(&self, state: &mut MState) { + for tok in &self.argv.flags { + self.add_value(state, &tok.atom, &tok.atom, &tok.arg); + } + } + + fn add_default_values(&self, state: &mut MState) { + lazy_static! { + static ref SPLIT_SPACE: Regex = regex!(r"\s+"); + } + let vs = &mut state.vals; + for (a, opts) in self.argv.dopt.descs.iter() { + if vs.contains_key(a) { + continue + } + let atom = a.clone(); + match (opts.repeats, &opts.arg) { + (false, &Zero) => { + match *a { + Positional(_) => vs.insert(atom, Plain(None)), + _ => vs.insert(atom, Switch(false)), + }; + } + (true, &Zero) => { + match *a { + Positional(_) => vs.insert(atom, List(vec!())), + _ => vs.insert(atom, Counted(0)), + }; + } + (false, &One(None)) => { vs.insert(atom, Plain(None)); } + (true, &One(None)) => { vs.insert(atom, List(vec!())); } + (false, &One(Some(ref v))) => { + vs.insert(atom, Plain(Some(v.clone()))); + } + (true, &One(Some(ref v))) => { + let words = SPLIT_SPACE + .split(v) + .map(|s| s.to_owned()) + .collect(); + vs.insert(atom, List(words)); + } + } + } + } + + fn state_consumed_all_argv(&self, state: &MState) -> bool { + self.argv.positional.len() == state.argvi + } + + fn state_has_valid_flags(&self, state: &MState) -> bool { + self.argv.counts.keys().all(|flag| state.max_counts.contains_key(flag)) + } + + fn state_valid_num_flags(&self, state: &MState) -> bool { + state.counts.iter().all( + |(flag, count)| count <= &state.max_counts[flag]) + } + + fn states(&self, pat: &Pattern, init: &MState) -> Vec { + match *pat { + Alternates(ref ps) => { + let mut alt_states = vec!(); + for p in ps.iter() { + alt_states.extend(self.states(p, init).into_iter()); + } + alt_states + } + Sequence(ref ps) => { + let (mut states, mut next) = (vec!(), vec!()); + let mut iter = ps.iter(); + match iter.next() { + None => return vec!(init.clone()), + Some(p) => states.extend(self.states(p, init).into_iter()), + } + for p in iter { + for s in states.into_iter() { + next.extend(self.states(p, &s).into_iter()); + } + states = vec!(); + states.extend(next.into_iter()); + next = vec!(); + } + states + } + Optional(ref ps) => { + let mut base = init.clone(); + let mut noflags = vec!(); + for p in ps.iter() { + match p { + // Prevent exponential growth in cases like [--flag...] + // See https://github.com/docopt/docopt.rs/issues/195 + &Repeat(ref b) => match &**b { + &PatAtom(ref a @ Short(_)) + | &PatAtom(ref a @ Long(_)) => { + let argv_count = self.argv.counts.get(a) + .map_or(0, |&x| x); + let max_count = base.max_counts.get(a) + .map_or(0, |&x| x); + if argv_count > max_count { + for _ in max_count..argv_count { + base.use_optional_flag(a); + } + } + } + _ => { + noflags.push(p); + } + }, + &PatAtom(ref a @ Short(_)) + | &PatAtom(ref a @ Long(_)) => { + let argv_count = self.argv.counts.get(a) + .map_or(0, |&x| x); + let max_count = base.max_counts.get(a) + .map_or(0, |&x| x); + if argv_count > max_count { + base.use_optional_flag(a); + } + } + other => { + noflags.push(other); + } + } + } + let mut states = vec!(); + self.all_option_states(&base, &mut states, &*noflags); + states + } + Repeat(ref p) => { match &**p { + &PatAtom(ref a @ Short(_)) + | &PatAtom(ref a @ Long(_)) => { + let mut bases = self.states(&**p, init); + for base in &mut bases { + let argv_count = self.argv.counts.get(a) + .map_or(0, |&x| x); + let max_count = base.max_counts.get(a) + .map_or(0, |&x| x); + if argv_count > max_count { + for _ in max_count..argv_count { + base.use_optional_flag(a); + } + } + } + bases + } + _ => { + let mut grouped_states = vec!(self.states(&**p, init)); + loop { + let mut nextss = vec!(); + for s in grouped_states.last().unwrap().iter() { + nextss.extend( + self.states(&**p, s) + .into_iter() + .filter(|snext| snext != s)); + } + if nextss.is_empty() { + break + } + grouped_states.push(nextss); + } + grouped_states + .into_iter() + .flat_map(|ss| ss.into_iter()) + .collect::>() + } + }} + PatAtom(ref atom) => { + let mut state = init.clone(); + match *atom { + Short(_) | Long(_) => { + if !state.use_flag(atom) { + return vec!() + } + } + Command(_) | Positional(_) => { + let tok = + match self.token_from(init) { + None => return vec!(), + Some(tok) => tok, + }; + let tok = + match state.match_cmd_or_posarg(atom, tok) { + None => return vec!(), + Some(tok) => tok, + }; + if !self.add_value(&mut state, atom, + &tok.atom, &tok.arg) { + return vec!() + } + } + } + vec!(state) + } + } + } + + fn all_option_states(&self, base: &MState, states: &mut Vec, + pats: &[&Pattern]) { + if pats.is_empty() { + states.push(base.clone()); + } else { + let (pat, rest) = (*pats.first().unwrap(), &pats[1..]); + for s in self.states(pat, base).into_iter() { + self.all_option_states(&s, states, rest); + } + // Order is important here! This must come after the loop above + // because we prefer presence over absence. The first state wins. + self.all_option_states(base, states, &pats[1..]); + } + } +} + +// Tries to parse a long flag of the form '--flag[=arg]' and returns a tuple +// with the flag atom and whether there is an argument or not. +// If '=arg' exists and 'arg' isn't a valid argument, an error is returned. +fn parse_long_equal(flag: &str) -> Result<(Atom, Argument), String> { + lazy_static! { + static ref LONG_EQUAL: Regex = regex!("^(?P[^=]+)=(?P.+)$"); + } + match LONG_EQUAL.captures(flag) { + None => Ok((Atom::new(flag), Zero)), + Some(cap) => { + let arg = cap_or_empty(&cap, "arg"); + if !Atom::is_arg(arg) { + err!("Argument '{}' for flag '{}' is not in the \ + form ARG or .", flag, arg) + } + Ok((Atom::new(cap_or_empty(&cap, "name")), One(None))) + } + } +} + +fn parse_long_equal_argv(flag: &str) -> (Atom, Option) { + lazy_static! { + static ref LONG_EQUAL: Regex = regex!("^(?P[^=]+)=(?P.*)$"); + } + match LONG_EQUAL.captures(flag) { + None => (Atom::new(flag), None), + Some(cap) => ( + Atom::new(cap_or_empty(&cap, "name")), + Some(cap_or_empty(&cap, "arg").to_string()), + ), + } +} + +// Tokenizes a usage pattern. +// Beware: regex hack ahead. Tokenizes based on whitespace separated words. +// It first normalizes `[xyz]` -> `[ xyz ]` so that delimiters are tokens. +// Similarly for `...`, `(`, `)` and `|`. +// One hitch: `--flag=` is allowed, so we use a regex to pick out +// words. +fn pattern_tokens(pat: &str) -> Vec { + lazy_static! { + static ref NORMALIZE: Regex = regex!(r"\.\.\.|\[|\]|\(|\)|\|"); + static ref WORDS: Regex = regex!(r"--\S+?=<[^>]+>|<[^>]+>|\S+"); + } + + let pat = NORMALIZE.replace_all(pat.trim(), " $0 "); + let mut words = vec!(); + for cap in WORDS.captures_iter(&*pat) { + words.push(cap[0].to_string()); + } + words +} diff --git a/docopt-0.8.3/src/synonym.rs b/docopt-0.8.3/src/synonym.rs new file mode 100644 index 000000000..f64b229a4 --- /dev/null +++ b/docopt-0.8.3/src/synonym.rs @@ -0,0 +1,107 @@ +use std::collections::HashMap; +use std::collections::hash_map::{Iter, Keys}; +use std::fmt::Debug; +use std::hash::Hash; +use std::iter::{FromIterator, IntoIterator}; +use std::mem; + +#[derive(Clone)] +pub struct SynonymMap { + vals: HashMap, + syns: HashMap, +} + +impl SynonymMap { + pub fn new() -> SynonymMap { + SynonymMap { + vals: HashMap::new(), + syns: HashMap::new(), + } + } + + pub fn insert_synonym(&mut self, from: K, to: K) -> bool { + assert!(self.vals.contains_key(&to)); + self.syns.insert(from, to).is_none() + } + + pub fn keys(&self) -> Keys { + self.vals.keys() + } + + pub fn iter(&self) -> Iter { + self.vals.iter() + } + + pub fn synonyms(&self) -> Iter { + self.syns.iter() + } + + pub fn find(&self, k: &K) -> Option<&V> { + self.with_key(k, |k| self.vals.get(k)) + } + + pub fn contains_key(&self, k: &K) -> bool { + self.with_key(k, |k| self.vals.contains_key(k)) + } + + pub fn len(&self) -> usize { + self.vals.len() + } + + fn with_key(&self, k: &K, with: F) -> T where F: FnOnce(&K) -> T { + if self.syns.contains_key(k) { + with(&self.syns[k]) + } else { + with(k) + } + } +} + +impl SynonymMap { + pub fn resolve(&self, k: &K) -> K { + self.with_key(k, |k| k.clone()) + } + + pub fn get<'a>(&'a self, k: &K) -> &'a V { + self.find(k).unwrap() + } + + pub fn find_mut<'a>(&'a mut self, k: &K) -> Option<&'a mut V> { + if self.syns.contains_key(k) { + self.vals.get_mut(&self.syns[k]) + } else { + self.vals.get_mut(k) + } + } + + pub fn swap(&mut self, k: K, mut new: V) -> Option { + if self.syns.contains_key(&k) { + let old = self.vals.get_mut(&k).unwrap(); + mem::swap(old, &mut new); + Some(new) + } else { + self.vals.insert(k, new) + } + } + + pub fn insert(&mut self, k: K, v: V) -> bool { + self.swap(k, v).is_none() + } +} + +impl FromIterator<(K, V)> for SynonymMap { + fn from_iter>(iter: T) -> SynonymMap { + let mut map = SynonymMap::new(); + for (k, v) in iter { + map.insert(k, v); + } + map + } +} + +impl Debug for SynonymMap { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + self.vals.fmt(f)?; + write!(f, " (synomyns: {:?})", self.syns) + } +} diff --git a/docopt-0.8.3/src/test/mod.rs b/docopt-0.8.3/src/test/mod.rs new file mode 100644 index 000000000..29cd4a044 --- /dev/null +++ b/docopt-0.8.3/src/test/mod.rs @@ -0,0 +1,152 @@ +use std::collections::HashMap; +use {Docopt, ArgvMap, Error}; +use Value::{self, Switch, Plain}; + +fn get_args(doc: &str, argv: &[&'static str]) -> ArgvMap { + let dopt = match Docopt::new(doc) { + Err(err) => panic!("Invalid usage: {}", err), + Ok(dopt) => dopt, + }; + match dopt.argv(vec!["cmd"].iter().chain(argv.iter())).parse() { + Err(err) => panic!("{}", err), + Ok(vals) => vals, + } +} + +fn map_from_alist(alist: Vec<(&'static str, Value)>) + -> HashMap { + alist.into_iter().map(|(k, v)| (k.to_string(), v)).collect() +} + +fn same_args(expected: &HashMap, got: &ArgvMap) { + for (k, ve) in expected.iter() { + match got.map.find(k) { + None => panic!("EXPECTED has '{}' but GOT does not.", k), + Some(vg) => { + assert!(ve == vg, + "{}: EXPECTED = '{:?}' != '{:?}' = GOT", k, ve, vg) + } + } + } + for (k, vg) in got.map.iter() { + match got.map.find(k) { + None => panic!("GOT has '{}' but EXPECTED does not.", k), + Some(ve) => { + assert!(vg == ve, + "{}: GOT = '{:?}' != '{:?}' = EXPECTED", k, vg, ve) + } + } + } +} + +macro_rules! test_expect( + ($name:ident, $doc:expr, $args:expr, $expected:expr) => ( + #[test] + fn $name() { + let vals = get_args($doc, $args); + let expected = map_from_alist($expected); + same_args(&expected, &vals); + } + ); +); + +macro_rules! test_user_error( + ($name:ident, $doc:expr, $args:expr) => ( + #[test] + #[should_panic] + fn $name() { get_args($doc, $args); } + ); +); + +test_expect!(test_issue_13, "Usage: prog file ", &["file", "file"], + vec![("file", Switch(true)), + ("", Plain(Some("file".to_string())))]); + +test_expect!(test_issue_129, "Usage: prog [options] + +Options: + --foo ARG Foo foo.", + &["--foo=a b"], + vec![("--foo", Plain(Some("a b".into())))]); + +#[test] +fn regression_issue_12() { + const USAGE: &'static str = " + Usage: + whisper info + whisper update + whisper mark + "; + + #[derive(Deserialize, Debug)] + struct Args { + arg_file: String, + cmd_info: bool, + cmd_update: bool, + arg_timestamp: u64, + arg_value: f64, + } + + let dopt: Args = Docopt::new(USAGE) + .unwrap() + .argv(&["whisper", "mark", "./p/blah", "100"]) + .deserialize() + .unwrap(); + assert_eq!(dopt.arg_timestamp, 0); +} + +#[test] +fn regression_issue_195() { + const USAGE: &'static str = " + Usage: + slow [-abcdefghijklmnopqrs...] + "; + + let argv = &["slow", "-abcdefghijklmnopqrs"]; + let dopt : Docopt = Docopt::new(USAGE).unwrap().argv(argv); + + dopt.parse().unwrap(); +} + +#[test] +fn regression_issue_219() { + #[derive(Deserialize)] + struct Args { + arg_type: Vec, + arg_param: Vec, + } + + const USAGE: &'static str = " + Usage: + encode [-v ]... + "; + + let argv = &["encode", "-v", "bool", "true", "string", "foo"]; + let args: Args = Docopt::new(USAGE).unwrap().argv(argv).deserialize().unwrap(); + assert_eq!(args.arg_type, vec!["bool".to_owned(), "string".to_owned()]); + assert_eq!(args.arg_param, vec!["true".to_owned(), "foo".to_owned()]); +} + +#[test] +fn test_unit_struct() { + const USAGE: &'static str = " + Usage: + cargo version [options] + + Options: + -h, --help Print this message + "; + + #[derive(Deserialize)] + struct Options; + + let argv = &["cargo", "version"]; + let dopt: Result= Docopt::new(USAGE) + .unwrap() + .argv(argv) + .deserialize(); + assert!(dopt.is_ok()); +} + +mod testcases; +mod suggestions; diff --git a/docopt-0.8.3/src/test/suggestions.rs b/docopt-0.8.3/src/test/suggestions.rs new file mode 100644 index 000000000..77bf47fbb --- /dev/null +++ b/docopt-0.8.3/src/test/suggestions.rs @@ -0,0 +1,72 @@ +use {Docopt, Error}; + +fn get_suggestion(doc: &str, argv: &[&'static str]) -> Error { + let dopt = + match Docopt::new(doc) { + Err(err) => panic!("Invalid usage: {}", err), + Ok(dopt) => dopt, + }; + let mut argv: Vec<_> = argv.iter().map(|x| x.to_string()).collect(); + argv.insert(0, "prog".to_string()); + match dopt.argv(argv.into_iter()).parse() { + Err(err) => err, + Ok(_) => panic!("Should have been a user error"), + } +} + +macro_rules! test_suggest( + ($name:ident, $doc:expr, $args:expr, $expected:expr) => ( + #[test] + fn $name() { + let sg = get_suggestion($doc, $args); + println!("{}", sg); + match sg { + Error::WithProgramUsage(e, _) => { + match *e { + Error::Argv(msg) => { + println!("{:?}",msg); + assert_eq!(msg, $expected); + } + err => panic!("Error other than argv: {:?}", err) + } + }, + _ => panic!("Error without program usage") + } + } + ); +); + + +test_suggest!(test_suggest_1, "Usage: prog [--release]", &["--releas"], "Unknown flag: '--releas'. Did you mean '--release'?"); + +test_suggest!(test_suggest_2, +"Usage: prog [-a] + prog [-a] ... + prog [-e] + Options: + -a, --archive Copy everything. +", +&["-d"], "Unknown flag: '-d'"); + + +test_suggest!(test_suggest_3, +"Usage: prog [-a] + prog [-a] ... + prog [-e] + Options: + -a, --archive Copy everything. + -e, --export Export all the things. +", +&["--expotr"], "Unknown flag: '--expotr'. Did you mean '--export'?"); + + +test_suggest!(test_suggest_4, +"Usage: prog [--import] [--complete] +", +&["--mport", "--complte"], "Unknown flag: '--mport'. Did you mean '--import'?"); + +test_suggest!(test_suggest_5, +"Usage: prog [--import] [--complete] +", +&["--import", "--complte"], "Unknown flag: '--complte'. Did you mean '--complete'?"); + diff --git a/docopt-0.8.3/src/test/testcases.docopt b/docopt-0.8.3/src/test/testcases.docopt new file mode 100644 index 000000000..ec063fef9 --- /dev/null +++ b/docopt-0.8.3/src/test/testcases.docopt @@ -0,0 +1,1122 @@ +r"""Usage: prog + +""" +$ prog +{} + +$ prog --xxx +"user-error" + + +r"""Usage: prog [options] + +Options: -a All. + +""" +$ prog +{"-a": false} + +$ prog -a +{"-a": true} + +$ prog -x +"user-error" + + +r"""Usage: prog [options] + +Options: --all All. + +""" +$ prog +{"--all": false} + +$ prog --all +{"--all": true} + +$ prog --xxx +"user-error" + + +r"""Usage: prog [options] + +Options: -v, --verbose Verbose. + +""" +$ prog --verbose +{"--verbose": true} + +$ prog --ver +"user-error" + +$ prog -v +{"--verbose": true} + + +r"""Usage: prog [options] + +Options: -p PATH + +""" +$ prog -p home/ +{"-p": "home/"} + +$ prog -phome/ +{"-p": "home/"} + +$ prog -p +"user-error" + + +r"""Usage: prog [options] + +Options: --path + +""" +$ prog --path home/ +{"--path": "home/"} + +$ prog --path=home/ +{"--path": "home/"} + +$ prog --pa home/ +"user-error" + +$ prog --pa=home/ +"user-error" + +$ prog --path +"user-error" + + +r"""Usage: prog [options] + +Options: -p PATH, --path= Path to files. + +""" +$ prog -proot +{"--path": "root"} + + +r"""Usage: prog [options] + +Options: -p --path PATH Path to files. + +""" +$ prog -p root +{"--path": "root"} + +$ prog --path root +{"--path": "root"} + + +r"""Usage: prog [options] + +Options: + -p PATH Path to files [default: ./] + +""" +$ prog +{"-p": "./"} + +$ prog -phome +{"-p": "home"} + + +r"""UsAgE: prog [options] + +OpTiOnS: --path= Path to files + [dEfAuLt: /root] + +""" +$ prog +{"--path": "/root"} + +$ prog --path=home +{"--path": "home"} + + +r"""usage: prog [options] + +options: + -a Add + -r Remote + -m Message + +""" +$ prog -a -r -m Hello +{"-a": true, + "-r": true, + "-m": "Hello"} + +$ prog -armyourass +{"-a": true, + "-r": true, + "-m": "yourass"} + +$ prog -a -r +{"-a": true, + "-r": true, + "-m": null} + + +r"""Usage: prog [options] + +Options: --version + --verbose + +""" +$ prog --version +{"--version": true, + "--verbose": false} + +$ prog --verbose +{"--version": false, + "--verbose": true} + +$ prog --ver +"user-error" + +$ prog --verb +"user-error" + + +r"""usage: prog [-a -r -m ] + +options: + -a Add + -r Remote + -m Message + +""" +$ prog -armyourass +{"-a": true, + "-r": true, + "-m": "yourass"} + + +r"""usage: prog [-armMSG] + +options: -a Add + -r Remote + -m Message + +""" +$ prog -a -r -m Hello +{"-a": true, + "-r": true, + "-m": "Hello"} + + +r"""usage: prog -a -b + +options: + -a + -b + +""" +$ prog -a -b +{"-a": true, "-b": true} + +$ prog -b -a +{"-a": true, "-b": true} + +$ prog -a +"user-error" + +$ prog +"user-error" + + +r"""usage: prog (-a -b) + +options: -a + -b + +""" +$ prog -a -b +{"-a": true, "-b": true} + +$ prog -b -a +{"-a": true, "-b": true} + +$ prog -a +"user-error" + +$ prog +"user-error" + + +r"""usage: prog [-a] -b + +options: -a + -b + +""" +$ prog -a -b +{"-a": true, "-b": true} + +$ prog -b -a +{"-a": true, "-b": true} + +$ prog -a +"user-error" + +$ prog -b +{"-a": false, "-b": true} + +$ prog +"user-error" + + +r"""usage: prog [(-a -b)] + +options: -a + -b + +""" +$ prog -a -b +{"-a": true, "-b": true} + +$ prog -b -a +{"-a": true, "-b": true} + +$ prog -a +"user-error" + +$ prog -b +"user-error" + +$ prog +{"-a": false, "-b": false} + + +r"""usage: prog (-a|-b) + +options: -a + -b + +""" +$ prog -a -b +"user-error" + +$ prog +"user-error" + +$ prog -a +{"-a": true, "-b": false} + +$ prog -b +{"-a": false, "-b": true} + + +r"""usage: prog [ -a | -b ] + +options: -a + -b + +""" +$ prog -a -b +"user-error" + +$ prog +{"-a": false, "-b": false} + +$ prog -a +{"-a": true, "-b": false} + +$ prog -b +{"-a": false, "-b": true} + + +r"""usage: prog """ +$ prog 10 +{"": "10"} + +$ prog 10 20 +"user-error" + +$ prog +"user-error" + + +r"""usage: prog []""" +$ prog 10 +{"": "10"} + +$ prog 10 20 +"user-error" + +$ prog +{"": null} + + +r"""usage: prog """ +$ prog 10 20 40 +{"": "10", "": "20", "": "40"} + +$ prog 10 20 +"user-error" + +$ prog +"user-error" + + +r"""usage: prog [ ]""" +$ prog 10 20 40 +{"": "10", "": "20", "": "40"} + +$ prog 10 20 +{"": "10", "": "20", "": null} + +$ prog +"user-error" + + +r"""usage: prog [ | ]""" +$ prog 10 20 40 +"user-error" + +$ prog 20 40 +{"": null, "": "20", "": "40"} + +$ prog +{"": null, "": null, "": null} + + +r"""usage: prog ( --all | ) + +options: + --all + +""" +$ prog 10 --all +{"": "10", "--all": true, "": null} + +$ prog 10 +{"": null, "--all": false, "": "10"} + +$ prog +"user-error" + + +r"""usage: prog [ ]""" +$ prog 10 20 +{"": ["10", "20"]} + +$ prog 10 +{"": ["10"]} + +$ prog +{"": []} + + +r"""usage: prog [( )]""" +$ prog 10 20 +{"": ["10", "20"]} + +$ prog 10 +"user-error" + +$ prog +{"": []} + + +r"""usage: prog NAME...""" +$ prog 10 20 +{"NAME": ["10", "20"]} + +$ prog 10 +{"NAME": ["10"]} + +$ prog +"user-error" + + +r"""usage: prog [NAME]...""" +$ prog 10 20 +{"NAME": ["10", "20"]} + +$ prog 10 +{"NAME": ["10"]} + +$ prog +{"NAME": []} + + +r"""usage: prog [NAME...]""" +$ prog 10 20 +{"NAME": ["10", "20"]} + +$ prog 10 +{"NAME": ["10"]} + +$ prog +{"NAME": []} + + +r"""usage: prog [NAME [NAME ...]]""" +$ prog 10 20 +{"NAME": ["10", "20"]} + +$ prog 10 +{"NAME": ["10"]} + +$ prog +{"NAME": []} + + +r"""usage: prog (NAME | --foo NAME) + +options: --foo + +""" +$ prog 10 +{"NAME": "10", "--foo": false} + +$ prog --foo 10 +{"NAME": "10", "--foo": true} + +$ prog --foo=10 +"user-error" + + +r"""usage: prog (NAME | --foo) [--bar | NAME] + +options: --foo +options: --bar + +""" +$ prog 10 +{"NAME": ["10"], "--foo": false, "--bar": false} + +$ prog 10 20 +{"NAME": ["10", "20"], "--foo": false, "--bar": false} + +$ prog --foo --bar +{"NAME": [], "--foo": true, "--bar": true} + + +r"""Naval Fate. + +Usage: + prog ship new ... + prog ship [] move [--speed=] + prog ship shoot + prog mine (set|remove) [--moored|--drifting] + prog -h | --help + prog --version + +Options: + -h --help Show this screen. + --version Show version. + --speed= Speed in knots [default: 10]. + --moored Mored (anchored) mine. + --drifting Drifting mine. + +""" +$ prog ship Guardian move 150 300 --speed=20 +{"--drifting": false, + "--help": false, + "--moored": false, + "--speed": "20", + "--version": false, + "": ["Guardian"], + "": "150", + "": "300", + "mine": false, + "move": true, + "new": false, + "remove": false, + "set": false, + "ship": true, + "shoot": false} + + +r"""usage: prog --hello""" +$ prog --hello +{"--hello": true} + + +r"""usage: prog [--hello=]""" +$ prog +{"--hello": null} + +$ prog --hello wrld +{"--hello": "wrld"} + + +r"""usage: prog [-o]""" +$ prog +{"-o": false} + +$ prog -o +{"-o": true} + + +r"""usage: prog [-opr]""" +$ prog -op +{"-o": true, "-p": true, "-r": false} + + +r"""usage: prog --aabb | --aa""" +$ prog --aa +{"--aabb": false, "--aa": true} + +$ prog --a +"user-error" # not a unique prefix + +# +# Counting number of flags +# + +r"""Usage: prog -v""" +$ prog -v +{"-v": true} + + +r"""Usage: prog [-v -v]""" +$ prog +{"-v": 0} + +$ prog -v +{"-v": 1} + +$ prog -vv +{"-v": 2} + + +r"""Usage: prog -v ...""" +$ prog +"user-error" + +$ prog -v +{"-v": 1} + +$ prog -vv +{"-v": 2} + +$ prog -vvvvvv +{"-v": 6} + + +r"""Usage: prog [-v | -vv | -vvv] + +This one is probably most readable user-friednly variant. + +""" +$ prog +{"-v": 0} + +$ prog -v +{"-v": 1} + +$ prog -vv +{"-v": 2} + +$ prog -vvvv +"user-error" + + +r"""usage: prog [--ver --ver]""" +$ prog --ver --ver +{"--ver": 2} + + +# +# Counting commands +# + +r"""usage: prog [go]""" +$ prog go +{"go": true} + + +r"""usage: prog [go go]""" +$ prog +{"go": 0} + +$ prog go +{"go": 1} + +$ prog go go +{"go": 2} + +$ prog go go go +"user-error" + +r"""usage: prog go...""" +$ prog go go go go go +{"go": 5} + +# +# [options] does not include options from usage-pattern +# +r"""usage: prog [options] [-a] + +options: -a + -b +""" +$ prog -a +{"-a": true, "-b": false} + +$ prog -aa +"user-error" + +# +# Test [options] shourtcut +# + +r"""Usage: prog [options] A + +Options: + -q Be quiet + -v Be verbose. + +""" +$ prog arg +{"A": "arg", "-v": false, "-q": false} + +$ prog -v arg +{"A": "arg", "-v": true, "-q": false} + +$ prog -q arg +{"A": "arg", "-v": false, "-q": true} + +# +# Test single dash +# + +r"""usage: prog [-]""" + +$ prog - +{"-": true} + +$ prog +{"-": false} + +# +# If argument is repeated, its value should always be a list +# + +r"""usage: prog [NAME [NAME ...]]""" + +$ prog a b +{"NAME": ["a", "b"]} + +$ prog +{"NAME": []} + +# +# Option's argument defaults to null/None +# + +r"""usage: prog [options] + +options: + -a Add + -m Message + +""" +$ prog -a +{"-m": null, "-a": true} + +# +# Test options without description +# + +r"""usage: prog --hello""" +$ prog --hello +{"--hello": true} + +r"""usage: prog [--hello=]""" +$ prog +{"--hello": null} + +$ prog --hello wrld +{"--hello": "wrld"} + +r"""usage: prog [-o]""" +$ prog +{"-o": false} + +$ prog -o +{"-o": true} + +r"""usage: prog [-opr]""" +$ prog -op +{"-o": true, "-p": true, "-r": false} + +r"""usage: git [-v | --verbose]""" +$ prog -v +{"-v": true, "--verbose": false} + +r"""usage: git remote [-v | --verbose]""" +$ prog remote -v +{"remote": true, "-v": true, "--verbose": false} + +# +# Test empty usage pattern +# + +r"""usage: prog""" +$ prog +{} + +r"""usage: prog + prog +""" +$ prog 1 2 +{"": "1", "": "2"} + +$ prog +{"": null, "": null} + +r"""usage: prog + prog +""" +$ prog +{"": null, "": null} + +# +# Option's argument should not capture default value from usage pattern +# + +r"""usage: prog [--file=]""" +$ prog +{"--file": null} + +r"""usage: prog [--file=] + +options: --file + +""" +$ prog +{"--file": null} + +r"""Usage: prog [-a ] + +Options: -a, --address TCP address [default: localhost:6283]. + +""" +$ prog +{"--address": "localhost:6283"} + +# +# If option with argument could be repeated, +# its arguments should be accumulated into a list +# + +r"""usage: prog --long= ...""" + +$ prog --long one +{"--long": ["one"]} + +$ prog --long one --long two +{"--long": ["one", "two"]} + +# +# Test multiple elements repeated at once +# + +r"""usage: prog (go --speed=)...""" +$ prog go left --speed=5 go right --speed=9 +{"go": 2, "": ["left", "right"], "--speed": ["5", "9"]} + +# +# Required options should work with option shortcut +# + +r"""usage: prog [options] -a + +options: -a + +""" +$ prog -a +{"-a": true} + +# +# If option could be repeated its defaults should be split into a list +# + +r"""usage: prog [-o ]... + +options: -o [default: x] + +""" +$ prog -o this -o that +{"-o": ["this", "that"]} + +$ prog +{"-o": ["x"]} + +r"""usage: prog [-o ]... + +options: -o [default: x y] + +""" +$ prog -o this +{"-o": ["this"]} + +$ prog +{"-o": ["x", "y"]} + +# +# Test stacked option's argument +# + +r"""usage: prog -pPATH + +options: -p PATH + +""" +$ prog -pHOME +{"-p": "HOME"} + +# +# Issue 56: Repeated mutually exclusive args give nested lists sometimes +# + +r"""Usage: foo (--xx=X|--yy=Y)...""" +$ prog --xx=1 --yy=2 +{"--xx": ["1"], "--yy": ["2"]} + +# +# POSIXly correct tokenization +# + +r"""usage: prog []""" +$ prog f.txt +{"": "f.txt"} + +r"""usage: prog [--input=]...""" +$ prog --input a.txt --input=b.txt +{"--input": ["a.txt", "b.txt"]} + +# +# Issue 85: `[options]` shourtcut with multiple subcommands +# + +r"""usage: prog good [options] + prog fail [options] + +options: --loglevel=N + +""" +$ prog fail --loglevel 5 +{"--loglevel": "5", "fail": true, "good": false} + +# +# Usage-section syntax +# + +r"""usage:prog --foo""" +$ prog --foo +{"--foo": true} + +r"""PROGRAM USAGE: prog --foo""" +$ prog --foo +{"--foo": true} + +r"""Usage: prog --foo + prog --bar +NOT PART OF SECTION""" +$ prog --foo +{"--foo": true, "--bar": false} + +r"""Usage: + prog --foo + prog --bar + +NOT PART OF SECTION""" +$ prog --foo +{"--foo": true, "--bar": false} + +r"""Usage: + prog --foo + prog --bar +NOT PART OF SECTION""" +$ prog --foo +{"--foo": true, "--bar": false} + +# +# Options-section syntax +# + +r"""Usage: prog [options] + +global options: --foo +local options: --baz + --bar +other options: + --egg + --spam +-not-an-option- + +""" +$ prog --bar --egg +{"--bar": true, "--egg": true, "--spam": false} + +r"""Usage: prog [-a] [--] [...]""" +$ program -a +{"-a": true, "": []} + +r"""Usage: prog [-a] [--] [...]""" +$ program -- +{"-a": false, "": []} + +r"""Usage: prog [-a] [--] [...]""" +$ program -a -- -b +{"-a": true, "": ["-b"]} + +r"""Usage: prog [-a] [--] [...]""" +$ program -a -- -a +{"-a": true, "": ["-a"]} + +r"""Usage: prog [-a] [--] [...]""" +$ program -- -a +{"-a": false, "": ["-a"]} + +r"""Usage: prog test [options] [--] [...]""" +$ program test a -- -b +{"": ["a", "-b"]} + +r"""Usage: prog test [options] [--] [...]""" +$ program test -- -b +{"": ["-b"]} + +r"""Usage: prog test [options] [--] [...]""" +$ program test a -b +"user-error" + +r"""Usage: prog test [options] [--] [...]""" +$ program test -- -b -- +{"": ["-b", "--"]} + +r"""Usage: prog [options] + +Options: + -a ... Foo +""" +$ program +{"-a": 0} +$ program -a +{"-a": 1} +$ program -a -a +{"-a": 2} +$ program -aa +{"-a": 2} +$ program -a -a -a +{"-a": 3} +$ program -aaa +{"-a": 3} + +r"""Usage: prog [options] + +Options: + -a, --all ... Foo +""" +$ program +{"-a": 0} +$ program -a +{"-a": 1} +$ program -a --all +{"-a": 2} +$ program -aa --all +{"-a": 3} +$ program --all +{"-a": 1} +$ program --all --all +{"-a": 2} + +r"""Usage: prog [options] + +Options: + -a, --all ARG ... Foo +""" +$ program +{"-a": []} +$ program -a 1 +{"-a": ["1"]} +$ program -a 2 --all 3 +{"-a": ["2", "3"]} +$ program -a4 -a5 --all 6 +{"-a": ["4", "5", "6"]} +$ program --all 7 +{"-a": ["7"]} +$ program --all 8 --all 9 +{"-a": ["8", "9"]} + +r"""Usage: prog [options] + +Options: + --all ... Foo +""" +$ program +{"--all": 0} +$ program --all +{"--all": 1} +$ program --all --all +{"--all": 2} + +r"""Usage: prog [options] + +Options: + --all=ARG ... Foo +""" +$ program +{"--all": []} +$ program --all 1 +{"--all": ["1"]} +$ program --all 2 --all 3 +{"--all": ["2", "3"]} + +r"""Usage: prog [options] + +Options: + --all ... Foo +""" +$ program --all --all +"user-error" + +r"""Usage: prog [options] + +Options: + --all ARG ... Foo +""" +$ program --all foo --all bar +"user-error" + +r"""Usage: prog --speed=ARG""" +$ program --speed 20 +{"--speed": "20"} +$ program --speed=20 +{"--speed": "20"} +$ program --speed=-20 +{"--speed": "-20"} +$ program --speed -20 +{"--speed": "-20"} + +# +# Issue 187: Fails to parse a default value containing ']' +# + +r"""usage: prog [--datetime=] + +options: --datetime= Regex for datetimes [default: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}] + +""" +$ prog +{"--datetime": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}"} + +# +# Issue 137: -x-y being seen as a positional argument +# + +r"""Usage: prog [options] + +Options: + -x ARG + -y""" +$ prog -x-y +{"-x": "-y"} diff --git a/docopt-0.8.3/src/test/testcases.rs b/docopt-0.8.3/src/test/testcases.rs new file mode 100644 index 000000000..c64c6fdeb --- /dev/null +++ b/docopt-0.8.3/src/test/testcases.rs @@ -0,0 +1,801 @@ +// !!! ATTENTION !!! +// This file is automatically generated by `scripts/mk-testcases`. +// Please do not edit this file directly! + +use Value::{Switch, Counted, Plain, List}; +use test::{get_args, map_from_alist, same_args}; + +test_expect!(test_0_testcases, "Usage: prog", &[], vec!()); + +test_user_error!(test_1_testcases, "Usage: prog", &["--xxx"]); + +test_expect!(test_2_testcases, "Usage: prog [options] + +Options: -a All.", &[], vec!(("-a", Switch(false)))); + +test_expect!(test_3_testcases, "Usage: prog [options] + +Options: -a All.", &["-a"], vec!(("-a", Switch(true)))); + +test_user_error!(test_4_testcases, "Usage: prog [options] + +Options: -a All.", &["-x"]); + +test_expect!(test_5_testcases, "Usage: prog [options] + +Options: --all All.", &[], vec!(("--all", Switch(false)))); + +test_expect!(test_6_testcases, "Usage: prog [options] + +Options: --all All.", &["--all"], vec!(("--all", Switch(true)))); + +test_user_error!(test_7_testcases, "Usage: prog [options] + +Options: --all All.", &["--xxx"]); + +test_expect!(test_8_testcases, "Usage: prog [options] + +Options: -v, --verbose Verbose.", &["--verbose"], vec!(("--verbose", Switch(true)))); + +test_user_error!(test_9_testcases, "Usage: prog [options] + +Options: -v, --verbose Verbose.", &["--ver"]); + +test_expect!(test_10_testcases, "Usage: prog [options] + +Options: -v, --verbose Verbose.", &["-v"], vec!(("--verbose", Switch(true)))); + +test_expect!(test_11_testcases, "Usage: prog [options] + +Options: -p PATH", &["-p", "home/"], vec!(("-p", Plain(Some("home/".to_string()))))); + +test_expect!(test_12_testcases, "Usage: prog [options] + +Options: -p PATH", &["-phome/"], vec!(("-p", Plain(Some("home/".to_string()))))); + +test_user_error!(test_13_testcases, "Usage: prog [options] + +Options: -p PATH", &["-p"]); + +test_expect!(test_14_testcases, "Usage: prog [options] + +Options: --path ", &["--path", "home/"], vec!(("--path", Plain(Some("home/".to_string()))))); + +test_expect!(test_15_testcases, "Usage: prog [options] + +Options: --path ", &["--path=home/"], vec!(("--path", Plain(Some("home/".to_string()))))); + +test_user_error!(test_16_testcases, "Usage: prog [options] + +Options: --path ", &["--pa", "home/"]); + +test_user_error!(test_17_testcases, "Usage: prog [options] + +Options: --path ", &["--pa=home/"]); + +test_user_error!(test_18_testcases, "Usage: prog [options] + +Options: --path ", &["--path"]); + +test_expect!(test_19_testcases, "Usage: prog [options] + +Options: -p PATH, --path= Path to files.", &["-proot"], vec!(("--path", Plain(Some("root".to_string()))))); + +test_expect!(test_20_testcases, "Usage: prog [options] + +Options: -p --path PATH Path to files.", &["-p", "root"], vec!(("--path", Plain(Some("root".to_string()))))); + +test_expect!(test_21_testcases, "Usage: prog [options] + +Options: -p --path PATH Path to files.", &["--path", "root"], vec!(("--path", Plain(Some("root".to_string()))))); + +test_expect!(test_22_testcases, "Usage: prog [options] + +Options: + -p PATH Path to files [default: ./]", &[], vec!(("-p", Plain(Some("./".to_string()))))); + +test_expect!(test_23_testcases, "Usage: prog [options] + +Options: + -p PATH Path to files [default: ./]", &["-phome"], vec!(("-p", Plain(Some("home".to_string()))))); + +test_expect!(test_24_testcases, "UsAgE: prog [options] + +OpTiOnS: --path= Path to files + [dEfAuLt: /root]", &[], vec!(("--path", Plain(Some("/root".to_string()))))); + +test_expect!(test_25_testcases, "UsAgE: prog [options] + +OpTiOnS: --path= Path to files + [dEfAuLt: /root]", &["--path=home"], vec!(("--path", Plain(Some("home".to_string()))))); + +test_expect!(test_26_testcases, "usage: prog [options] + +options: + -a Add + -r Remote + -m Message", &["-a", "-r", "-m", "Hello"], vec!(("-m", Plain(Some("Hello".to_string()))), ("-a", Switch(true)), ("-r", Switch(true)))); + +test_expect!(test_27_testcases, "usage: prog [options] + +options: + -a Add + -r Remote + -m Message", &["-armyourass"], vec!(("-m", Plain(Some("yourass".to_string()))), ("-a", Switch(true)), ("-r", Switch(true)))); + +test_expect!(test_28_testcases, "usage: prog [options] + +options: + -a Add + -r Remote + -m Message", &["-a", "-r"], vec!(("-m", Plain(None)), ("-a", Switch(true)), ("-r", Switch(true)))); + +test_expect!(test_29_testcases, "Usage: prog [options] + +Options: --version + --verbose", &["--version"], vec!(("--verbose", Switch(false)), ("--version", Switch(true)))); + +test_expect!(test_30_testcases, "Usage: prog [options] + +Options: --version + --verbose", &["--verbose"], vec!(("--verbose", Switch(true)), ("--version", Switch(false)))); + +test_user_error!(test_31_testcases, "Usage: prog [options] + +Options: --version + --verbose", &["--ver"]); + +test_user_error!(test_32_testcases, "Usage: prog [options] + +Options: --version + --verbose", &["--verb"]); + +test_expect!(test_33_testcases, "usage: prog [-a -r -m ] + +options: + -a Add + -r Remote + -m Message", &["-armyourass"], vec!(("-m", Plain(Some("yourass".to_string()))), ("-a", Switch(true)), ("-r", Switch(true)))); + +test_expect!(test_34_testcases, "usage: prog [-armMSG] + +options: -a Add + -r Remote + -m Message", &["-a", "-r", "-m", "Hello"], vec!(("-m", Plain(Some("Hello".to_string()))), ("-a", Switch(true)), ("-r", Switch(true)))); + +test_expect!(test_35_testcases, "usage: prog -a -b + +options: + -a + -b", &["-a", "-b"], vec!(("-a", Switch(true)), ("-b", Switch(true)))); + +test_expect!(test_36_testcases, "usage: prog -a -b + +options: + -a + -b", &["-b", "-a"], vec!(("-a", Switch(true)), ("-b", Switch(true)))); + +test_user_error!(test_37_testcases, "usage: prog -a -b + +options: + -a + -b", &["-a"]); + +test_user_error!(test_38_testcases, "usage: prog -a -b + +options: + -a + -b", &[]); + +test_expect!(test_39_testcases, "usage: prog (-a -b) + +options: -a + -b", &["-a", "-b"], vec!(("-a", Switch(true)), ("-b", Switch(true)))); + +test_expect!(test_40_testcases, "usage: prog (-a -b) + +options: -a + -b", &["-b", "-a"], vec!(("-a", Switch(true)), ("-b", Switch(true)))); + +test_user_error!(test_41_testcases, "usage: prog (-a -b) + +options: -a + -b", &["-a"]); + +test_user_error!(test_42_testcases, "usage: prog (-a -b) + +options: -a + -b", &[]); + +test_expect!(test_43_testcases, "usage: prog [-a] -b + +options: -a + -b", &["-a", "-b"], vec!(("-a", Switch(true)), ("-b", Switch(true)))); + +test_expect!(test_44_testcases, "usage: prog [-a] -b + +options: -a + -b", &["-b", "-a"], vec!(("-a", Switch(true)), ("-b", Switch(true)))); + +test_user_error!(test_45_testcases, "usage: prog [-a] -b + +options: -a + -b", &["-a"]); + +test_expect!(test_46_testcases, "usage: prog [-a] -b + +options: -a + -b", &["-b"], vec!(("-a", Switch(false)), ("-b", Switch(true)))); + +test_user_error!(test_47_testcases, "usage: prog [-a] -b + +options: -a + -b", &[]); + +test_expect!(test_48_testcases, "usage: prog [(-a -b)] + +options: -a + -b", &["-a", "-b"], vec!(("-a", Switch(true)), ("-b", Switch(true)))); + +test_expect!(test_49_testcases, "usage: prog [(-a -b)] + +options: -a + -b", &["-b", "-a"], vec!(("-a", Switch(true)), ("-b", Switch(true)))); + +test_user_error!(test_50_testcases, "usage: prog [(-a -b)] + +options: -a + -b", &["-a"]); + +test_user_error!(test_51_testcases, "usage: prog [(-a -b)] + +options: -a + -b", &["-b"]); + +test_expect!(test_52_testcases, "usage: prog [(-a -b)] + +options: -a + -b", &[], vec!(("-a", Switch(false)), ("-b", Switch(false)))); + +test_user_error!(test_53_testcases, "usage: prog (-a|-b) + +options: -a + -b", &["-a", "-b"]); + +test_user_error!(test_54_testcases, "usage: prog (-a|-b) + +options: -a + -b", &[]); + +test_expect!(test_55_testcases, "usage: prog (-a|-b) + +options: -a + -b", &["-a"], vec!(("-a", Switch(true)), ("-b", Switch(false)))); + +test_expect!(test_56_testcases, "usage: prog (-a|-b) + +options: -a + -b", &["-b"], vec!(("-a", Switch(false)), ("-b", Switch(true)))); + +test_user_error!(test_57_testcases, "usage: prog [ -a | -b ] + +options: -a + -b", &["-a", "-b"]); + +test_expect!(test_58_testcases, "usage: prog [ -a | -b ] + +options: -a + -b", &[], vec!(("-a", Switch(false)), ("-b", Switch(false)))); + +test_expect!(test_59_testcases, "usage: prog [ -a | -b ] + +options: -a + -b", &["-a"], vec!(("-a", Switch(true)), ("-b", Switch(false)))); + +test_expect!(test_60_testcases, "usage: prog [ -a | -b ] + +options: -a + -b", &["-b"], vec!(("-a", Switch(false)), ("-b", Switch(true)))); + +test_expect!(test_61_testcases, "usage: prog ", &["10"], vec!(("", Plain(Some("10".to_string()))))); + +test_user_error!(test_62_testcases, "usage: prog ", &["10", "20"]); + +test_user_error!(test_63_testcases, "usage: prog ", &[]); + +test_expect!(test_64_testcases, "usage: prog []", &["10"], vec!(("", Plain(Some("10".to_string()))))); + +test_user_error!(test_65_testcases, "usage: prog []", &["10", "20"]); + +test_expect!(test_66_testcases, "usage: prog []", &[], vec!(("", Plain(None)))); + +test_expect!(test_67_testcases, "usage: prog ", &["10", "20", "40"], vec!(("", Plain(Some("40".to_string()))), ("", Plain(Some("10".to_string()))), ("", Plain(Some("20".to_string()))))); + +test_user_error!(test_68_testcases, "usage: prog ", &["10", "20"]); + +test_user_error!(test_69_testcases, "usage: prog ", &[]); + +test_expect!(test_70_testcases, "usage: prog [ ]", &["10", "20", "40"], vec!(("", Plain(Some("40".to_string()))), ("", Plain(Some("10".to_string()))), ("", Plain(Some("20".to_string()))))); + +test_expect!(test_71_testcases, "usage: prog [ ]", &["10", "20"], vec!(("", Plain(None)), ("", Plain(Some("10".to_string()))), ("", Plain(Some("20".to_string()))))); + +test_user_error!(test_72_testcases, "usage: prog [ ]", &[]); + +test_user_error!(test_73_testcases, "usage: prog [ | ]", &["10", "20", "40"]); + +test_expect!(test_74_testcases, "usage: prog [ | ]", &["20", "40"], vec!(("", Plain(Some("40".to_string()))), ("", Plain(None)), ("", Plain(Some("20".to_string()))))); + +test_expect!(test_75_testcases, "usage: prog [ | ]", &[], vec!(("", Plain(None)), ("", Plain(None)), ("", Plain(None)))); + +test_expect!(test_76_testcases, "usage: prog ( --all | ) + +options: + --all", &["10", "--all"], vec!(("--all", Switch(true)), ("", Plain(Some("10".to_string()))), ("", Plain(None)))); + +test_expect!(test_77_testcases, "usage: prog ( --all | ) + +options: + --all", &["10"], vec!(("--all", Switch(false)), ("", Plain(None)), ("", Plain(Some("10".to_string()))))); + +test_user_error!(test_78_testcases, "usage: prog ( --all | ) + +options: + --all", &[]); + +test_expect!(test_79_testcases, "usage: prog [ ]", &["10", "20"], vec!(("", List(vec!("10".to_string(), "20".to_string()))))); + +test_expect!(test_80_testcases, "usage: prog [ ]", &["10"], vec!(("", List(vec!("10".to_string()))))); + +test_expect!(test_81_testcases, "usage: prog [ ]", &[], vec!(("", List(vec!())))); + +test_expect!(test_82_testcases, "usage: prog [( )]", &["10", "20"], vec!(("", List(vec!("10".to_string(), "20".to_string()))))); + +test_user_error!(test_83_testcases, "usage: prog [( )]", &["10"]); + +test_expect!(test_84_testcases, "usage: prog [( )]", &[], vec!(("", List(vec!())))); + +test_expect!(test_85_testcases, "usage: prog NAME...", &["10", "20"], vec!(("NAME", List(vec!("10".to_string(), "20".to_string()))))); + +test_expect!(test_86_testcases, "usage: prog NAME...", &["10"], vec!(("NAME", List(vec!("10".to_string()))))); + +test_user_error!(test_87_testcases, "usage: prog NAME...", &[]); + +test_expect!(test_88_testcases, "usage: prog [NAME]...", &["10", "20"], vec!(("NAME", List(vec!("10".to_string(), "20".to_string()))))); + +test_expect!(test_89_testcases, "usage: prog [NAME]...", &["10"], vec!(("NAME", List(vec!("10".to_string()))))); + +test_expect!(test_90_testcases, "usage: prog [NAME]...", &[], vec!(("NAME", List(vec!())))); + +test_expect!(test_91_testcases, "usage: prog [NAME...]", &["10", "20"], vec!(("NAME", List(vec!("10".to_string(), "20".to_string()))))); + +test_expect!(test_92_testcases, "usage: prog [NAME...]", &["10"], vec!(("NAME", List(vec!("10".to_string()))))); + +test_expect!(test_93_testcases, "usage: prog [NAME...]", &[], vec!(("NAME", List(vec!())))); + +test_expect!(test_94_testcases, "usage: prog [NAME [NAME ...]]", &["10", "20"], vec!(("NAME", List(vec!("10".to_string(), "20".to_string()))))); + +test_expect!(test_95_testcases, "usage: prog [NAME [NAME ...]]", &["10"], vec!(("NAME", List(vec!("10".to_string()))))); + +test_expect!(test_96_testcases, "usage: prog [NAME [NAME ...]]", &[], vec!(("NAME", List(vec!())))); + +test_expect!(test_97_testcases, "usage: prog (NAME | --foo NAME) + +options: --foo", &["10"], vec!(("NAME", Plain(Some("10".to_string()))), ("--foo", Switch(false)))); + +test_expect!(test_98_testcases, "usage: prog (NAME | --foo NAME) + +options: --foo", &["--foo", "10"], vec!(("NAME", Plain(Some("10".to_string()))), ("--foo", Switch(true)))); + +test_user_error!(test_99_testcases, "usage: prog (NAME | --foo NAME) + +options: --foo", &["--foo=10"]); + +test_expect!(test_100_testcases, "usage: prog (NAME | --foo) [--bar | NAME] + +options: --foo +options: --bar", &["10"], vec!(("--bar", Switch(false)), ("NAME", List(vec!("10".to_string()))), ("--foo", Switch(false)))); + +test_expect!(test_101_testcases, "usage: prog (NAME | --foo) [--bar | NAME] + +options: --foo +options: --bar", &["10", "20"], vec!(("--bar", Switch(false)), ("NAME", List(vec!("10".to_string(), "20".to_string()))), ("--foo", Switch(false)))); + +test_expect!(test_102_testcases, "usage: prog (NAME | --foo) [--bar | NAME] + +options: --foo +options: --bar", &["--foo", "--bar"], vec!(("--bar", Switch(true)), ("NAME", List(vec!())), ("--foo", Switch(true)))); + +test_expect!(test_103_testcases, "Naval Fate. + +Usage: + prog ship new ... + prog ship [] move [--speed=] + prog ship shoot + prog mine (set|remove) [--moored|--drifting] + prog -h | --help + prog --version + +Options: + -h --help Show this screen. + --version Show version. + --speed= Speed in knots [default: 10]. + --moored Mored (anchored) mine. + --drifting Drifting mine.", &["ship", "Guardian", "move", "150", "300", "--speed=20"], vec!(("shoot", Switch(false)), ("--moored", Switch(false)), ("--drifting", Switch(false)), ("move", Switch(true)), ("--speed", Plain(Some("20".to_string()))), ("mine", Switch(false)), ("new", Switch(false)), ("--version", Switch(false)), ("set", Switch(false)), ("remove", Switch(false)), ("", List(vec!("Guardian".to_string()))), ("ship", Switch(true)), ("", Plain(Some("150".to_string()))), ("", Plain(Some("300".to_string()))), ("--help", Switch(false)))); + +test_expect!(test_104_testcases, "usage: prog --hello", &["--hello"], vec!(("--hello", Switch(true)))); + +test_expect!(test_105_testcases, "usage: prog [--hello=]", &[], vec!(("--hello", Plain(None)))); + +test_expect!(test_106_testcases, "usage: prog [--hello=]", &["--hello", "wrld"], vec!(("--hello", Plain(Some("wrld".to_string()))))); + +test_expect!(test_107_testcases, "usage: prog [-o]", &[], vec!(("-o", Switch(false)))); + +test_expect!(test_108_testcases, "usage: prog [-o]", &["-o"], vec!(("-o", Switch(true)))); + +test_expect!(test_109_testcases, "usage: prog [-opr]", &["-op"], vec!(("-o", Switch(true)), ("-p", Switch(true)), ("-r", Switch(false)))); + +test_expect!(test_110_testcases, "usage: prog --aabb | --aa", &["--aa"], vec!(("--aa", Switch(true)), ("--aabb", Switch(false)))); + +test_user_error!(test_111_testcases, "usage: prog --aabb | --aa", &["--a"]); + +test_expect!(test_112_testcases, "Usage: prog -v", &["-v"], vec!(("-v", Switch(true)))); + +test_expect!(test_113_testcases, "Usage: prog [-v -v]", &[], vec!(("-v", Counted(0)))); + +test_expect!(test_114_testcases, "Usage: prog [-v -v]", &["-v"], vec!(("-v", Counted(1)))); + +test_expect!(test_115_testcases, "Usage: prog [-v -v]", &["-vv"], vec!(("-v", Counted(2)))); + +test_user_error!(test_116_testcases, "Usage: prog -v ...", &[]); + +test_expect!(test_117_testcases, "Usage: prog -v ...", &["-v"], vec!(("-v", Counted(1)))); + +test_expect!(test_118_testcases, "Usage: prog -v ...", &["-vv"], vec!(("-v", Counted(2)))); + +test_expect!(test_119_testcases, "Usage: prog -v ...", &["-vvvvvv"], vec!(("-v", Counted(6)))); + +test_expect!(test_120_testcases, "Usage: prog [-v | -vv | -vvv] + +This one is probably most readable user-friednly variant.", &[], vec!(("-v", Counted(0)))); + +test_expect!(test_121_testcases, "Usage: prog [-v | -vv | -vvv] + +This one is probably most readable user-friednly variant.", &["-v"], vec!(("-v", Counted(1)))); + +test_expect!(test_122_testcases, "Usage: prog [-v | -vv | -vvv] + +This one is probably most readable user-friednly variant.", &["-vv"], vec!(("-v", Counted(2)))); + +test_user_error!(test_123_testcases, "Usage: prog [-v | -vv | -vvv] + +This one is probably most readable user-friednly variant.", &["-vvvv"]); + +test_expect!(test_124_testcases, "usage: prog [--ver --ver]", &["--ver", "--ver"], vec!(("--ver", Counted(2)))); + +test_expect!(test_125_testcases, "usage: prog [go]", &["go"], vec!(("go", Switch(true)))); + +test_expect!(test_126_testcases, "usage: prog [go go]", &[], vec!(("go", Counted(0)))); + +test_expect!(test_127_testcases, "usage: prog [go go]", &["go"], vec!(("go", Counted(1)))); + +test_expect!(test_128_testcases, "usage: prog [go go]", &["go", "go"], vec!(("go", Counted(2)))); + +test_user_error!(test_129_testcases, "usage: prog [go go]", &["go", "go", "go"]); + +test_expect!(test_130_testcases, "usage: prog go...", &["go", "go", "go", "go", "go"], vec!(("go", Counted(5)))); + +test_expect!(test_131_testcases, "usage: prog [options] [-a] + +options: -a + -b", &["-a"], vec!(("-a", Switch(true)), ("-b", Switch(false)))); + +test_user_error!(test_132_testcases, "usage: prog [options] [-a] + +options: -a + -b", &["-aa"]); + +test_expect!(test_133_testcases, "Usage: prog [options] A + +Options: + -q Be quiet + -v Be verbose.", &["arg"], vec!(("A", Plain(Some("arg".to_string()))), ("-v", Switch(false)), ("-q", Switch(false)))); + +test_expect!(test_134_testcases, "Usage: prog [options] A + +Options: + -q Be quiet + -v Be verbose.", &["-v", "arg"], vec!(("A", Plain(Some("arg".to_string()))), ("-v", Switch(true)), ("-q", Switch(false)))); + +test_expect!(test_135_testcases, "Usage: prog [options] A + +Options: + -q Be quiet + -v Be verbose.", &["-q", "arg"], vec!(("A", Plain(Some("arg".to_string()))), ("-v", Switch(false)), ("-q", Switch(true)))); + +test_expect!(test_136_testcases, "usage: prog [-]", &["-"], vec!(("-", Switch(true)))); + +test_expect!(test_137_testcases, "usage: prog [-]", &[], vec!(("-", Switch(false)))); + +test_expect!(test_138_testcases, "usage: prog [NAME [NAME ...]]", &["a", "b"], vec!(("NAME", List(vec!("a".to_string(), "b".to_string()))))); + +test_expect!(test_139_testcases, "usage: prog [NAME [NAME ...]]", &[], vec!(("NAME", List(vec!())))); + +test_expect!(test_140_testcases, "usage: prog [options] + +options: + -a Add + -m Message", &["-a"], vec!(("-m", Plain(None)), ("-a", Switch(true)))); + +test_expect!(test_141_testcases, "usage: prog --hello", &["--hello"], vec!(("--hello", Switch(true)))); + +test_expect!(test_142_testcases, "usage: prog [--hello=]", &[], vec!(("--hello", Plain(None)))); + +test_expect!(test_143_testcases, "usage: prog [--hello=]", &["--hello", "wrld"], vec!(("--hello", Plain(Some("wrld".to_string()))))); + +test_expect!(test_144_testcases, "usage: prog [-o]", &[], vec!(("-o", Switch(false)))); + +test_expect!(test_145_testcases, "usage: prog [-o]", &["-o"], vec!(("-o", Switch(true)))); + +test_expect!(test_146_testcases, "usage: prog [-opr]", &["-op"], vec!(("-o", Switch(true)), ("-p", Switch(true)), ("-r", Switch(false)))); + +test_expect!(test_147_testcases, "usage: git [-v | --verbose]", &["-v"], vec!(("-v", Switch(true)), ("--verbose", Switch(false)))); + +test_expect!(test_148_testcases, "usage: git remote [-v | --verbose]", &["remote", "-v"], vec!(("-v", Switch(true)), ("remote", Switch(true)), ("--verbose", Switch(false)))); + +test_expect!(test_149_testcases, "usage: prog", &[], vec!()); + +test_expect!(test_150_testcases, "usage: prog + prog ", &["1", "2"], vec!(("", Plain(Some("1".to_string()))), ("", Plain(Some("2".to_string()))))); + +test_expect!(test_151_testcases, "usage: prog + prog ", &[], vec!(("", Plain(None)), ("", Plain(None)))); + +test_expect!(test_152_testcases, "usage: prog + prog", &[], vec!(("", Plain(None)), ("", Plain(None)))); + +test_expect!(test_153_testcases, "usage: prog [--file=]", &[], vec!(("--file", Plain(None)))); + +test_expect!(test_154_testcases, "usage: prog [--file=] + +options: --file ", &[], vec!(("--file", Plain(None)))); + +test_expect!(test_155_testcases, "Usage: prog [-a ] + +Options: -a, --address TCP address [default: localhost:6283].", &[], vec!(("--address", Plain(Some("localhost:6283".to_string()))))); + +test_expect!(test_156_testcases, "usage: prog --long= ...", &["--long", "one"], vec!(("--long", List(vec!("one".to_string()))))); + +test_expect!(test_157_testcases, "usage: prog --long= ...", &["--long", "one", "--long", "two"], vec!(("--long", List(vec!("one".to_string(), "two".to_string()))))); + +test_expect!(test_158_testcases, "usage: prog (go --speed=)...", &["go", "left", "--speed=5", "go", "right", "--speed=9"], vec!(("go", Counted(2)), ("", List(vec!("left".to_string(), "right".to_string()))), ("--speed", List(vec!("5".to_string(), "9".to_string()))))); + +test_expect!(test_159_testcases, "usage: prog [options] -a + +options: -a", &["-a"], vec!(("-a", Switch(true)))); + +test_expect!(test_160_testcases, "usage: prog [-o ]... + +options: -o [default: x]", &["-o", "this", "-o", "that"], vec!(("-o", List(vec!("this".to_string(), "that".to_string()))))); + +test_expect!(test_161_testcases, "usage: prog [-o ]... + +options: -o [default: x]", &[], vec!(("-o", List(vec!("x".to_string()))))); + +test_expect!(test_162_testcases, "usage: prog [-o ]... + +options: -o [default: x y]", &["-o", "this"], vec!(("-o", List(vec!("this".to_string()))))); + +test_expect!(test_163_testcases, "usage: prog [-o ]... + +options: -o [default: x y]", &[], vec!(("-o", List(vec!("x".to_string(), "y".to_string()))))); + +test_expect!(test_164_testcases, "usage: prog -pPATH + +options: -p PATH", &["-pHOME"], vec!(("-p", Plain(Some("HOME".to_string()))))); + +test_expect!(test_165_testcases, "Usage: foo (--xx=X|--yy=Y)...", &["--xx=1", "--yy=2"], vec!(("--yy", List(vec!("2".to_string()))), ("--xx", List(vec!("1".to_string()))))); + +test_expect!(test_166_testcases, "usage: prog []", &["f.txt"], vec!(("", Plain(Some("f.txt".to_string()))))); + +test_expect!(test_167_testcases, "usage: prog [--input=]...", &["--input", "a.txt", "--input=b.txt"], vec!(("--input", List(vec!("a.txt".to_string(), "b.txt".to_string()))))); + +test_expect!(test_168_testcases, "usage: prog good [options] + prog fail [options] + +options: --loglevel=N", &["fail", "--loglevel", "5"], vec!(("fail", Switch(true)), ("good", Switch(false)), ("--loglevel", Plain(Some("5".to_string()))))); + +test_expect!(test_169_testcases, "usage:prog --foo", &["--foo"], vec!(("--foo", Switch(true)))); + +test_expect!(test_170_testcases, "PROGRAM USAGE: prog --foo", &["--foo"], vec!(("--foo", Switch(true)))); + +test_expect!(test_171_testcases, "Usage: prog --foo + prog --bar +NOT PART OF SECTION", &["--foo"], vec!(("--bar", Switch(false)), ("--foo", Switch(true)))); + +test_expect!(test_172_testcases, "Usage: + prog --foo + prog --bar + +NOT PART OF SECTION", &["--foo"], vec!(("--bar", Switch(false)), ("--foo", Switch(true)))); + +test_expect!(test_173_testcases, "Usage: + prog --foo + prog --bar +NOT PART OF SECTION", &["--foo"], vec!(("--bar", Switch(false)), ("--foo", Switch(true)))); + +test_expect!(test_174_testcases, "Usage: prog [options] + +global options: --foo +local options: --baz + --bar +other options: + --egg + --spam +-not-an-option-", &["--bar", "--egg"], vec!(("--bar", Switch(true)), ("--egg", Switch(true)), ("--spam", Switch(false)))); + +test_expect!(test_175_testcases, "Usage: prog [-a] [--] [...]", &["-a"], vec!(("", List(vec!())), ("-a", Switch(true)))); + +test_expect!(test_176_testcases, "Usage: prog [-a] [--] [...]", &["--"], vec!(("", List(vec!())), ("-a", Switch(false)))); + +test_expect!(test_177_testcases, "Usage: prog [-a] [--] [...]", &["-a", "--", "-b"], vec!(("", List(vec!("-b".to_string()))), ("-a", Switch(true)))); + +test_expect!(test_178_testcases, "Usage: prog [-a] [--] [...]", &["-a", "--", "-a"], vec!(("", List(vec!("-a".to_string()))), ("-a", Switch(true)))); + +test_expect!(test_179_testcases, "Usage: prog [-a] [--] [...]", &["--", "-a"], vec!(("", List(vec!("-a".to_string()))), ("-a", Switch(false)))); + +test_expect!(test_180_testcases, "Usage: prog test [options] [--] [...]", &["test", "a", "--", "-b"], vec!(("", List(vec!("a".to_string(), "-b".to_string()))))); + +test_expect!(test_181_testcases, "Usage: prog test [options] [--] [...]", &["test", "--", "-b"], vec!(("", List(vec!("-b".to_string()))))); + +test_user_error!(test_182_testcases, "Usage: prog test [options] [--] [...]", &["test", "a", "-b"]); + +test_expect!(test_183_testcases, "Usage: prog test [options] [--] [...]", &["test", "--", "-b", "--"], vec!(("", List(vec!("-b".to_string(), "--".to_string()))))); + +test_expect!(test_184_testcases, "Usage: prog [options] + +Options: + -a ... Foo", &[], vec!(("-a", Counted(0)))); + +test_expect!(test_185_testcases, "Usage: prog [options] + +Options: + -a ... Foo", &["-a"], vec!(("-a", Counted(1)))); + +test_expect!(test_186_testcases, "Usage: prog [options] + +Options: + -a ... Foo", &["-a", "-a"], vec!(("-a", Counted(2)))); + +test_expect!(test_187_testcases, "Usage: prog [options] + +Options: + -a ... Foo", &["-aa"], vec!(("-a", Counted(2)))); + +test_expect!(test_188_testcases, "Usage: prog [options] + +Options: + -a ... Foo", &["-a", "-a", "-a"], vec!(("-a", Counted(3)))); + +test_expect!(test_189_testcases, "Usage: prog [options] + +Options: + -a ... Foo", &["-aaa"], vec!(("-a", Counted(3)))); + +test_expect!(test_190_testcases, "Usage: prog [options] + +Options: + -a, --all ... Foo", &[], vec!(("-a", Counted(0)))); + +test_expect!(test_191_testcases, "Usage: prog [options] + +Options: + -a, --all ... Foo", &["-a"], vec!(("-a", Counted(1)))); + +test_expect!(test_192_testcases, "Usage: prog [options] + +Options: + -a, --all ... Foo", &["-a", "--all"], vec!(("-a", Counted(2)))); + +test_expect!(test_193_testcases, "Usage: prog [options] + +Options: + -a, --all ... Foo", &["-aa", "--all"], vec!(("-a", Counted(3)))); + +test_expect!(test_194_testcases, "Usage: prog [options] + +Options: + -a, --all ... Foo", &["--all"], vec!(("-a", Counted(1)))); + +test_expect!(test_195_testcases, "Usage: prog [options] + +Options: + -a, --all ... Foo", &["--all", "--all"], vec!(("-a", Counted(2)))); + +test_expect!(test_196_testcases, "Usage: prog [options] + +Options: + -a, --all ARG ... Foo", &[], vec!(("-a", List(vec!())))); + +test_expect!(test_197_testcases, "Usage: prog [options] + +Options: + -a, --all ARG ... Foo", &["-a", "1"], vec!(("-a", List(vec!("1".to_string()))))); + +test_expect!(test_198_testcases, "Usage: prog [options] + +Options: + -a, --all ARG ... Foo", &["-a", "2", "--all", "3"], vec!(("-a", List(vec!("2".to_string(), "3".to_string()))))); + +test_expect!(test_199_testcases, "Usage: prog [options] + +Options: + -a, --all ARG ... Foo", &["-a4", "-a5", "--all", "6"], vec!(("-a", List(vec!("4".to_string(), "5".to_string(), "6".to_string()))))); + +test_expect!(test_200_testcases, "Usage: prog [options] + +Options: + -a, --all ARG ... Foo", &["--all", "7"], vec!(("-a", List(vec!("7".to_string()))))); + +test_expect!(test_201_testcases, "Usage: prog [options] + +Options: + -a, --all ARG ... Foo", &["--all", "8", "--all", "9"], vec!(("-a", List(vec!("8".to_string(), "9".to_string()))))); + +test_expect!(test_202_testcases, "Usage: prog [options] + +Options: + --all ... Foo", &[], vec!(("--all", Counted(0)))); + +test_expect!(test_203_testcases, "Usage: prog [options] + +Options: + --all ... Foo", &["--all"], vec!(("--all", Counted(1)))); + +test_expect!(test_204_testcases, "Usage: prog [options] + +Options: + --all ... Foo", &["--all", "--all"], vec!(("--all", Counted(2)))); + +test_expect!(test_205_testcases, "Usage: prog [options] + +Options: + --all=ARG ... Foo", &[], vec!(("--all", List(vec!())))); + +test_expect!(test_206_testcases, "Usage: prog [options] + +Options: + --all=ARG ... Foo", &["--all", "1"], vec!(("--all", List(vec!("1".to_string()))))); + +test_expect!(test_207_testcases, "Usage: prog [options] + +Options: + --all=ARG ... Foo", &["--all", "2", "--all", "3"], vec!(("--all", List(vec!("2".to_string(), "3".to_string()))))); + +test_user_error!(test_208_testcases, "Usage: prog [options] + +Options: + --all ... Foo", &["--all", "--all"]); + +test_user_error!(test_209_testcases, "Usage: prog [options] + +Options: + --all ARG ... Foo", &["--all", "foo", "--all", "bar"]); + +test_expect!(test_210_testcases, "Usage: prog --speed=ARG", &["--speed", "20"], vec!(("--speed", Plain(Some("20".to_string()))))); + +test_expect!(test_211_testcases, "Usage: prog --speed=ARG", &["--speed=20"], vec!(("--speed", Plain(Some("20".to_string()))))); + +test_expect!(test_212_testcases, "Usage: prog --speed=ARG", &["--speed=-20"], vec!(("--speed", Plain(Some("-20".to_string()))))); + +test_expect!(test_213_testcases, "Usage: prog --speed=ARG", &["--speed", "-20"], vec!(("--speed", Plain(Some("-20".to_string()))))); + +test_expect!(test_214_testcases, "usage: prog [--datetime=] + +options: --datetime= Regex for datetimes [default: ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}]", &[], vec!(("--datetime", Plain(Some("^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}".to_string()))))); + +test_expect!(test_215_testcases, "Usage: prog [options] + +Options: + -x ARG + -y", &["-x-y"], vec!(("-x", Plain(Some("-y".to_string()))))); + diff --git a/docopt-0.8.3/src/wordlist.rs b/docopt-0.8.3/src/wordlist.rs new file mode 100644 index 000000000..1adada79a --- /dev/null +++ b/docopt-0.8.3/src/wordlist.rs @@ -0,0 +1,114 @@ +#[macro_use] +extern crate lazy_static; + +#[macro_use] +extern crate serde_derive; + +extern crate regex; +extern crate serde; +extern crate strsim; + +use std::collections::HashMap; +use std::io::{self, Read, Write}; + +use dopt::Docopt; +use parse::{Atom, Parser}; + +// cheat until we get syntax extensions back :-( +macro_rules! regex( + ($s:expr) => (::regex::Regex::new($s).unwrap()); +); + +macro_rules! werr( + ($($arg:tt)*) => ({ + use std::io::{Write, stderr}; + write!(&mut stderr(), $($arg)*).unwrap(); + }) +); + +fn cap_or_empty<'t>(caps: ®ex::Captures<'t>, name: &str) -> &'t str { + caps.name(name).map_or("", |m| m.as_str()) +} + +#[allow(dead_code)] +mod dopt; +#[allow(dead_code)] +mod parse; +#[allow(dead_code)] +mod synonym; + +const USAGE: &'static str = " +Usage: docopt-wordlist [( )] ... + +docopt-wordlist prints a list of available flags and commands arguments for the +given usage (provided on stdin). + +Example use: + + your-command --help | docopt-wordlist + +This command also supports completing positional arguments when given a list of +choices. The choices are included in the word list if and only if the argument +name appears in the usage string. For example: + + your-command --help | docopt-wordlist 'arg' 'a b c' + +Which will only include 'a', 'b' and 'c' in the wordlist if +'your-command --help' contains a positional argument named 'arg'. +"; + +#[derive(Debug, Deserialize)] +struct Args { + arg_name: Vec, + arg_possibles: Vec, +} + +fn main() { + let args: Args = Docopt::new(USAGE) + .and_then(|d| d.deserialize()) + .unwrap_or_else(|e| e.exit()); + match run(args) { + Ok(_) => {}, + Err(err) => { + write!(&mut io::stderr(), "{}", err).unwrap(); + ::std::process::exit(1) + } + } +} + +fn run(args: Args) -> Result<(), String> { + let mut usage = String::new(); + io::stdin().read_to_string(&mut usage).map_err(|e| e.to_string())?; + let parsed = Parser::new(&usage).map_err(|e| e.to_string())?; + let arg_possibles: HashMap> = + args.arg_name.iter() + .zip(args.arg_possibles.iter()) + .map(|(name, possibles)| { + let choices = + regex!(r"[ \t]+").split(&**possibles) + .map(|s| s.to_string()) + .collect::>(); + (name.clone(), choices) + }) + .collect(); + + let mut words = vec![]; + for k in parsed.descs.keys() { + if let Atom::Positional(ref arg_name) = *k { + if let Some(choices) = arg_possibles.get(arg_name) { + words.extend(choices.iter().map(|s| s.clone())); + } + // If the user hasn't given choices for this positional argument, + // then there's really nothing to complete here. + } else { + words.push(k.to_string()); + } + } + for (k, _) in parsed.descs.synonyms() { + // We don't need to do anything special here since synonyms can + // only be flags, which we always include in the wordlist. + words.push(k.to_string()); + } + println!("{}", words.join(" ")); + Ok(()) +} diff --git a/dtoa-0.4.2/.cargo-checksum.json b/dtoa-0.4.2/.cargo-checksum.json new file mode 100644 index 000000000..03f5daad8 --- /dev/null +++ b/dtoa-0.4.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"} \ No newline at end of file diff --git a/dtoa-0.4.2/.travis.yml b/dtoa-0.4.2/.travis.yml new file mode 100644 index 000000000..0e4e98974 --- /dev/null +++ b/dtoa-0.4.2/.travis.yml @@ -0,0 +1,6 @@ +sudo: false + +language: rust + +rust: + - nightly diff --git a/dtoa-0.4.2/Cargo.toml b/dtoa-0.4.2/Cargo.toml new file mode 100644 index 000000000..d61e1defd --- /dev/null +++ b/dtoa-0.4.2/Cargo.toml @@ -0,0 +1,23 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "dtoa" +version = "0.4.2" +authors = ["David Tolnay "] +exclude = ["performance.png"] +description = "Fast functions for printing floating-point primitives to an io::Write" +documentation = "https://github.com/dtolnay/dtoa" +readme = "README.md" +categories = ["value-formatting"] +license = "MIT/Apache-2.0" +repository = "https://github.com/dtolnay/dtoa" diff --git a/dtoa-0.4.2/LICENSE-APACHE b/dtoa-0.4.2/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/dtoa-0.4.2/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/dtoa-0.4.2/LICENSE-MIT b/dtoa-0.4.2/LICENSE-MIT new file mode 100644 index 000000000..d1c35df03 --- /dev/null +++ b/dtoa-0.4.2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2016 Itoa Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/dtoa-0.4.2/README.md b/dtoa-0.4.2/README.md new file mode 100644 index 000000000..2f26b68a5 --- /dev/null +++ b/dtoa-0.4.2/README.md @@ -0,0 +1,69 @@ +dtoa +==== + +[![Build Status](https://api.travis-ci.org/dtolnay/dtoa.svg?branch=master)](https://travis-ci.org/dtolnay/dtoa) +[![Latest Version](https://img.shields.io/crates/v/dtoa.svg)](https://crates.io/crates/dtoa) + +This crate provides fast functions for printing floating-point primitives to an +[`io::Write`](https://doc.rust-lang.org/std/io/trait.Write.html). The +implementation is a straightforward Rust port of [Milo +Yip](https://github.com/miloyip)'s C++ implementation +[dtoa.h](https://github.com/miloyip/rapidjson/blob/master/include/rapidjson/internal/dtoa.h). +The original C++ code of each function is included in comments. + +See also [`itoa`](https://github.com/dtolnay/itoa) for printing integer +primitives. + +## Performance (lower is better) + +![performance](https://raw.githubusercontent.com/dtolnay/dtoa/master/performance.png) + +## Functions + +```rust +extern crate dtoa; + +// write to a vector or other io::Write +let mut buf = Vec::new(); +dtoa::write(&mut buf, 2.71828f64)?; +println!("{:?}", buf); + +// write to a stack buffer +let mut bytes = [b'\0'; 20]; +let n = dtoa::write(&mut bytes[..], 2.71828f64)?; +println!("{:?}", &bytes[..n]); +``` + +The function signature is: + +```rust +fn write(writer: W, value: V) -> io::Result<()> +``` + +where `dtoa::Floating` is implemented for `f32` and `f64`. The return value +gives the number of bytes written. + +## Dependency + +Dtoa is available on [crates.io](https://crates.io/crates/dtoa). Use the +following in `Cargo.toml`: + +```toml +[dependencies] +dtoa = "0.4" +``` + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in dtoa by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/dtoa-0.4.2/benches/bench.rs b/dtoa-0.4.2/benches/bench.rs new file mode 100644 index 000000000..ec5795356 --- /dev/null +++ b/dtoa-0.4.2/benches/bench.rs @@ -0,0 +1,54 @@ +#![feature(test)] + +extern crate dtoa; +extern crate test; + +macro_rules! benches { + ($($name:ident($value:expr),)*) => { + mod bench_dtoa { + use test::{Bencher, black_box}; + $( + #[bench] + fn $name(b: &mut Bencher) { + use dtoa; + + let mut buf = Vec::with_capacity(20); + + b.iter(|| { + buf.clear(); + dtoa::write(&mut buf, black_box($value)).unwrap() + }); + } + )* + } + + mod bench_fmt { + use test::{Bencher, black_box}; + $( + #[bench] + fn $name(b: &mut Bencher) { + use std::io::Write; + + let mut buf = Vec::with_capacity(20); + + b.iter(|| { + buf.clear(); + write!(&mut buf, "{}", black_box($value)).unwrap() + }); + } + )* + } + } +} + +benches!( + bench_0_f64(0f64), + bench_short_f64(0.1234f64), + bench_e_f64(2.718281828459045f64), + bench_max_f64(::std::f64::MAX), + + bench_0_f32(0f32), + bench_short_f32(0.1234f32), + bench_e_f32(2.718281828459045f32), + bench_max_f32(::std::f32::MAX), +); diff --git a/dtoa-0.4.2/src/diyfp.rs b/dtoa-0.4.2/src/diyfp.rs new file mode 100644 index 000000000..758dde67d --- /dev/null +++ b/dtoa-0.4.2/src/diyfp.rs @@ -0,0 +1,232 @@ +// Copyright 2016 Dtoa Developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops; + +#[derive(Copy, Clone, Debug)] +pub struct DiyFp { + pub f: F, + pub e: E, +} + +impl DiyFp { + pub fn new(f: F, e: E) -> Self { + DiyFp { f: f, e: e } + } +} + +impl ops::Mul for DiyFp { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + let mut tmp = self.f as u64 * rhs.f as u64; + tmp += 1u64 << 31; // mult_round + DiyFp { + f: (tmp >> 32) as u32, + e: self.e + rhs.e + 32, + } + } +} + +impl ops::Mul for DiyFp { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + let m32 = 0xFFFFFFFFu64; + let a = self.f >> 32; + let b = self.f & m32; + let c = rhs.f >> 32; + let d = rhs.f & m32; + let ac = a * c; + let bc = b * c; + let ad = a * d; + let bd = b * d; + let mut tmp = (bd >> 32) + (ad & m32) + (bc & m32); + tmp += 1u64 << 31; // mult_round + DiyFp { + f: ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), + e: self.e + rhs.e + 64, + } + } +} + +#[macro_export] +macro_rules! diyfp {( + floating_type: $fty:ty, + significand_type: $sigty:ty, + exponent_type: $expty:ty, + + diy_significand_size: $diy_significand_size:expr, + significand_size: $significand_size:expr, + exponent_bias: $exponent_bias:expr, + mask_type: $mask_type:ty, + exponent_mask: $exponent_mask:expr, + significand_mask: $significand_mask:expr, + hidden_bit: $hidden_bit:expr, + cached_powers_f: $cached_powers_f:expr, + cached_powers_e: $cached_powers_e:expr, + min_power: $min_power:expr, +) => { + +type DiyFp = diyfp::DiyFp<$sigty, $expty>; + +impl DiyFp { + // Preconditions: + // `d` must have a positive sign and must not be infinity or NaN. + /* + explicit DiyFp(double d) { + union { + double d; + uint64_t u64; + } u = { d }; + + int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); + uint64_t significand = (u.u64 & kDpSignificandMask); + if (biased_e != 0) { + f = significand + kDpHiddenBit; + e = biased_e - kDpExponentBias; + } + else { + f = significand; + e = kDpMinExponent + 1; + } + } + */ + unsafe fn from(d: $fty) -> Self { + let u: $mask_type = mem::transmute(d); + + let biased_e = ((u & $exponent_mask) >> $significand_size) as $expty; + let significand = u & $significand_mask; + if biased_e != 0 { + DiyFp { + f: significand + $hidden_bit, + e: biased_e - $exponent_bias - $significand_size, + } + } else { + DiyFp { + f: significand, + e: 1 - $exponent_bias - $significand_size, + } + } + } + + // Normalizes so that the highest bit of the diy significand is 1. + /* + DiyFp Normalize() const { + DiyFp res = *this; + while (!(res.f & (static_cast(1) << 63))) { + res.f <<= 1; + res.e--; + } + return res; + } + */ + fn normalize(self) -> DiyFp { + let mut res = self; + while (res.f & (1 << ($diy_significand_size - 1))) == 0 { + res.f <<= 1; + res.e -= 1; + } + res + } + + // Normalizes so that the highest bit of the diy significand is 1. + // + // Precondition: + // `self.f` must be no more than 2 bits longer than the f64 significand. + /* + DiyFp NormalizeBoundary() const { + DiyFp res = *this; + while (!(res.f & (kDpHiddenBit << 1))) { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); + return res; + } + */ + fn normalize_boundary(self) -> DiyFp { + let mut res = self; + while (res.f & $hidden_bit << 1) == 0 { + res.f <<= 1; + res.e -= 1; + } + res.f <<= $diy_significand_size - $significand_size - 2; + res.e -= $diy_significand_size - $significand_size - 2; + res + } + + // Normalizes `self - e` and `self + e` where `e` is half of the least + // significant digit of `self`. The plus is normalized so that the highest + // bit of the diy significand is 1. The minus is normalized so that it has + // the same exponent as the plus. + // + // Preconditions: + // `self` must have been returned directly from `DiyFp::from_f64`. + // `self.f` must not be zero. + /* + void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { + DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); + DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *plus = pl; + *minus = mi; + } + */ + fn normalized_boundaries(self) -> (DiyFp, DiyFp) { + let pl = DiyFp::new((self.f << 1) + 1, self.e - 1).normalize_boundary(); + let mut mi = if self.f == $hidden_bit { + DiyFp::new((self.f << 2) - 1, self.e - 2) + } else { + DiyFp::new((self.f << 1) - 1, self.e - 1) + }; + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + (mi, pl) + } +} + +impl ops::Sub for DiyFp { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + DiyFp { + f: self.f - rhs.f, + e: self.e, + } + } +} + +/* +inline DiyFp GetCachedPower(int e, int* K) { + //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; + double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive + int k = static_cast(dk); + if (dk - k > 0.0) + k++; + + unsigned index = static_cast((k >> 3) + 1); + *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table + + return GetCachedPowerByIndex(index); +} +*/ +#[inline] +fn get_cached_power(e: $expty) -> (DiyFp, isize) { + let dk = (3 - $diy_significand_size - e) as f64 * 0.30102999566398114f64 - ($min_power + 1) as f64; + let mut k = dk as isize; + if dk - k as f64 > 0.0 { + k += 1; + } + + let index = ((k >> 3) + 1) as usize; + let k = -($min_power + (index << 3) as isize); + + (DiyFp::new($cached_powers_f[index], $cached_powers_e[index] as $expty), k) +} + +}} diff --git a/dtoa-0.4.2/src/dtoa.rs b/dtoa-0.4.2/src/dtoa.rs new file mode 100644 index 000000000..5c10833d1 --- /dev/null +++ b/dtoa-0.4.2/src/dtoa.rs @@ -0,0 +1,479 @@ +// Copyright 2016 Dtoa Developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_export] +macro_rules! dtoa {( + floating_type: $fty:ty, + significand_type: $sigty:ty, + exponent_type: $expty:ty, + $($diyfp_param:ident: $diyfp_value:tt,)* +) => { + +diyfp! { + floating_type: $fty, + significand_type: $sigty, + exponent_type: $expty, + $($diyfp_param: $diyfp_value,)* +}; + +/* +inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { + while (rest < wp_w && delta - rest >= ten_kappa && + (rest + ten_kappa < wp_w || /// closer + wp_w - rest > rest + ten_kappa - wp_w)) { + buffer[len - 1]--; + rest += ten_kappa; + } +} +*/ + +#[inline] +unsafe fn grisu_round(buffer: *mut u8, len: isize, delta: $sigty, mut rest: $sigty, ten_kappa: $sigty, wp_w: $sigty) { + while rest < wp_w && delta - rest >= ten_kappa && + (rest + ten_kappa < wp_w || // closer + wp_w - rest > rest + ten_kappa - wp_w) { + *buffer.offset(len - 1) -= 1; + rest += ten_kappa; + } +} + +/* +inline unsigned CountDecimalDigit32(uint32_t n) { + // Simple pure C++ implementation was faster than __builtin_clz version in this situation. + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1000) return 3; + if (n < 10000) return 4; + if (n < 100000) return 5; + if (n < 1000000) return 6; + if (n < 10000000) return 7; + if (n < 100000000) return 8; + // Will not reach 10 digits in DigitGen() + //if (n < 1000000000) return 9; + //return 10; + return 9; +} +*/ + +#[inline] +fn count_decimal_digit32(n: u32) -> usize { + if n < 10 { 1 } + else if n < 100 { 2 } + else if n < 1000 { 3 } + else if n < 10000 { 4 } + else if n < 100000 { 5 } + else if n < 1000000 { 6 } + else if n < 10000000 { 7 } + else if n < 100000000 { 8 } + // Will not reach 10 digits in digit_gen() + else { 9 } +} + +/* +inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { + static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); + const DiyFp wp_w = Mp - W; + uint32_t p1 = static_cast(Mp.f >> -one.e); + uint64_t p2 = Mp.f & (one.f - 1); + unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] + *len = 0; +*/ + +// Returns length and k. +#[inline] +unsafe fn digit_gen(w: DiyFp, mp: DiyFp, mut delta: $sigty, buffer: *mut u8, mut k: isize) -> (isize, isize) { + static POW10: [$sigty; 10] = [ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 ]; + let one = DiyFp::new(1 << -mp.e, mp.e); + let wp_w = mp - w; + let mut p1 = (mp.f >> -one.e) as u32; + let mut p2 = mp.f & (one.f - 1); + let mut kappa = count_decimal_digit32(p1); // kappa in [0, 9] + let mut len = 0; + + /* + while (kappa > 0) { + uint32_t d = 0; + switch (kappa) { + case 9: d = p1 / 100000000; p1 %= 100000000; break; + case 8: d = p1 / 10000000; p1 %= 10000000; break; + case 7: d = p1 / 1000000; p1 %= 1000000; break; + case 6: d = p1 / 100000; p1 %= 100000; break; + case 5: d = p1 / 10000; p1 %= 10000; break; + case 4: d = p1 / 1000; p1 %= 1000; break; + case 3: d = p1 / 100; p1 %= 100; break; + case 2: d = p1 / 10; p1 %= 10; break; + case 1: d = p1; p1 = 0; break; + default:; + } + if (d || *len) + buffer[(*len)++] = static_cast('0' + static_cast(d)); + kappa--; + uint64_t tmp = (static_cast(p1) << -one.e) + p2; + if (tmp <= delta) { + *K += kappa; + GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); + return; + } + } + */ + while kappa > 0 { + let mut d = 0u32; + match kappa { + 9 => { d = p1 / 100000000; p1 %= 100000000; } + 8 => { d = p1 / 10000000; p1 %= 10000000; } + 7 => { d = p1 / 1000000; p1 %= 1000000; } + 6 => { d = p1 / 100000; p1 %= 100000; } + 5 => { d = p1 / 10000; p1 %= 10000; } + 4 => { d = p1 / 1000; p1 %= 1000; } + 3 => { d = p1 / 100; p1 %= 100; } + 2 => { d = p1 / 10; p1 %= 10; } + 1 => { d = p1; p1 = 0; } + _ => {} + } + if d != 0 || len != 0 { + *buffer.offset(len) = b'0' + d as u8; + len += 1; + } + kappa -= 1; + let tmp = (p1 as $sigty << -one.e) + p2; + if tmp <= delta { + k += kappa as isize; + grisu_round(buffer, len, delta, tmp, POW10[kappa] << -one.e, wp_w.f); + return (len, k); + } + } + + // kappa = 0 + /* + for (;;) { + p2 *= 10; + delta *= 10; + char d = static_cast(p2 >> -one.e); + if (d || *len) + buffer[(*len)++] = static_cast('0' + d); + p2 &= one.f - 1; + kappa--; + if (p2 < delta) { + *K += kappa; + int index = -static_cast(kappa); + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast(kappa)] : 0)); + return; + } + } + */ + loop { + p2 *= 10; + delta *= 10; + let d = (p2 >> -one.e) as u8; + if d != 0 || len != 0 { + *buffer.offset(len) = b'0' + d; + len += 1; + } + p2 &= one.f - 1; + kappa = kappa.wrapping_sub(1); + if p2 < delta { + k += kappa as isize; + let index = -(kappa as isize); + grisu_round(buffer, len, delta, p2, one.f, wp_w.f * if index < 9 { POW10[-(kappa as isize) as usize] } else { 0 }); + return (len, k); + } + } +} + +/* +inline void Grisu2(double value, char* buffer, int* length, int* K) { + const DiyFp v(value); + DiyFp w_m, w_p; + v.NormalizedBoundaries(&w_m, &w_p); + + const DiyFp c_mk = GetCachedPower(w_p.e, K); + const DiyFp W = v.Normalize() * c_mk; + DiyFp Wp = w_p * c_mk; + DiyFp Wm = w_m * c_mk; + Wm.f++; + Wp.f--; + DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); +} +*/ + +// Returns length and k. +#[inline] +unsafe fn grisu2(value: $fty, buffer: *mut u8) -> (isize, isize) { + let v = DiyFp::from(value); + let (w_m, w_p) = v.normalized_boundaries(); + + let (c_mk, k) = get_cached_power(w_p.e); + let w = v.normalize() * c_mk; + let mut wp = w_p * c_mk; + let mut wm = w_m * c_mk; + wm.f += 1; + wp.f -= 1; + digit_gen(w, wp, wp.f - wm.f, buffer, k) +} + +/* +inline char* WriteExponent(int K, char* buffer) { + if (K < 0) { + *buffer++ = '-'; + K = -K; + } + + if (K >= 100) { + *buffer++ = static_cast('0' + static_cast(K / 100)); + K %= 100; + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else if (K >= 10) { + const char* d = GetDigitsLut() + K * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + else + *buffer++ = static_cast('0' + static_cast(K)); + + return buffer; +} +*/ + +#[inline] +unsafe fn write_exponent(mut k: isize, mut buffer: *mut u8) -> *mut u8 { + if k < 0 { + *buffer = b'-'; + buffer = buffer.offset(1); + k = -k; + } + + if k >= 100 { + *buffer = b'0' + (k / 100) as u8; + k %= 100; + let d = DEC_DIGITS_LUT.as_ptr().offset(k * 2); + ptr::copy_nonoverlapping(d, buffer.offset(1), 2); + buffer.offset(3) + } else if k >= 10 { + let d = DEC_DIGITS_LUT.as_ptr().offset(k * 2); + ptr::copy_nonoverlapping(d, buffer, 2); + buffer.offset(2) + } else { + *buffer = b'0' + k as u8; + buffer.offset(1) + } +} + +/* +inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { + const int kk = length + k; // 10^(kk-1) <= v < 10^kk +*/ + +#[inline] +unsafe fn prettify(buffer: *mut u8, length: isize, k: isize) -> *mut u8 { + let kk = length + k; // 10^(kk-1) <= v < 10^kk + + /* + if (0 <= k && kk <= 21) { + // 1234e7 -> 12340000000 + for (int i = length; i < kk; i++) + buffer[i] = '0'; + buffer[kk] = '.'; + buffer[kk + 1] = '0'; + return &buffer[kk + 2]; + } + */ + if 0 <= k && kk <= 21 { + // 1234e7 -> 12340000000 + for i in length..kk { + *buffer.offset(i) = b'0'; + } + *buffer.offset(kk) = b'.'; + *buffer.offset(kk + 1) = b'0'; + buffer.offset(kk + 2) + } + + /* + else if (0 < kk && kk <= 21) { + // 1234e-2 -> 12.34 + std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); + buffer[kk] = '.'; + if (0 > k + maxDecimalPlaces) { + // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[kk + 2]; // Reserve one zero + } + else + return &buffer[length + 1]; + } + */ + else if 0 < kk && kk <= 21 { + // 1234e-2 -> 12.34 + ptr::copy(buffer.offset(kk), buffer.offset(kk + 1), (length - kk) as usize); + *buffer.offset(kk) = b'.'; + if 0 > k + MAX_DECIMAL_PLACES { + // When MAX_DECIMAL_PLACES = 2, 1.2345 -> 1.23, 1.102 -> 1.1 + // Remove extra trailing zeros (at least one) after truncation. + for i in (kk + 2 .. kk + MAX_DECIMAL_PLACES + 1).rev() { + if *buffer.offset(i) != b'0' { + return buffer.offset(i + 1); + } + } + buffer.offset(kk + 2) // Reserve one zero + } else { + buffer.offset(length + 1) + } + } + + /* + else if (-6 < kk && kk <= 0) { + // 1234e-6 -> 0.001234 + const int offset = 2 - kk; + std::memmove(&buffer[offset], &buffer[0], static_cast(length)); + buffer[0] = '0'; + buffer[1] = '.'; + for (int i = 2; i < offset; i++) + buffer[i] = '0'; + if (length - kk > maxDecimalPlaces) { + // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = maxDecimalPlaces + 1; i > 2; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[3]; // Reserve one zero + } + else + return &buffer[length + offset]; + } + */ + else if -6 < kk && kk <= 0 { + // 1234e-6 -> 0.001234 + let offset = 2 - kk; + ptr::copy(buffer, buffer.offset(offset), length as usize); + *buffer = b'0'; + *buffer.offset(1) = b'.'; + for i in 2..offset { + *buffer.offset(i) = b'0'; + } + if length - kk > MAX_DECIMAL_PLACES { + // When MAX_DECIMAL_PLACES = 2, 0.123 -> 0.12, 0.102 -> 0.1 + // Remove extra trailing zeros (at least one) after truncation. + for i in (3 .. MAX_DECIMAL_PLACES + 2).rev() { + if *buffer.offset(i) != b'0' { + return buffer.offset(i + 1); + } + } + buffer.offset(3) // Reserve one zero + } else { + buffer.offset(length + offset) + } + } + + /* + else if (kk < -maxDecimalPlaces) { + // Truncate to zero + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + */ + else if kk < -MAX_DECIMAL_PLACES { + *buffer = b'0'; + *buffer.offset(1) = b'.'; + *buffer.offset(2) = b'0'; + buffer.offset(3) + } + + /* + else if (length == 1) { + // 1e30 + buffer[1] = 'e'; + return WriteExponent(kk - 1, &buffer[2]); + } + */ + else if length == 1 { + // 1e30 + *buffer.offset(1) = b'e'; + write_exponent(kk - 1, buffer.offset(2)) + } + + /* + else { + // 1234e30 -> 1.234e33 + std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); + buffer[1] = '.'; + buffer[length + 1] = 'e'; + return WriteExponent(kk - 1, &buffer[0 + length + 2]); + } + */ + else { + // 1234e30 -> 1.234e33 + ptr::copy(buffer.offset(1), buffer.offset(2), (length - 1) as usize); + *buffer.offset(1) = b'.'; + *buffer.offset(length + 1) = b'e'; + write_exponent(kk - 1, buffer.offset(length + 2)) + } +} + +/* +inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { + RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); + Double d(value); + if (d.IsZero()) { + if (d.Sign()) + *buffer++ = '-'; // -0.0, Issue #289 + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; + } + else { + if (value < 0) { + *buffer++ = '-'; + value = -value; + } + int length, K; + Grisu2(value, buffer, &length, &K); + return Prettify(buffer, length, K, maxDecimalPlaces); + } +} +*/ + +#[inline] +unsafe fn dtoa(mut wr: W, mut value: $fty) -> io::Result { + if value == 0.0 { + if value.is_sign_negative() { + try!(wr.write_all(b"-0.0")); + Ok(4) + } else { + try!(wr.write_all(b"0.0")); + Ok(3) + } + } else { + let negative = value < 0.0; + if negative { + try!(wr.write_all(b"-")); + value = -value; + } + let mut buffer: [u8; 24] = mem::uninitialized(); + let buf_ptr = buffer.as_mut_ptr(); + let (length, k) = grisu2(value, buf_ptr); + let end = prettify(buf_ptr, length, k); + let len = end as usize - buf_ptr as usize; + try!(wr.write_all(slice::from_raw_parts(buf_ptr, len))); + if negative { + Ok(len + 1) + } else { + Ok(len) + } + } +} + +}} diff --git a/dtoa-0.4.2/src/lib.rs b/dtoa-0.4.2/src/lib.rs new file mode 100644 index 000000000..a0f9454cd --- /dev/null +++ b/dtoa-0.4.2/src/lib.rs @@ -0,0 +1,148 @@ +// Copyright 2016 Dtoa Developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![doc(html_root_url = "https://docs.rs/dtoa/0.4.2")] + +#[macro_use] mod diyfp; +#[macro_use] mod dtoa; + +use std::{io, mem, ops, ptr, slice}; + +#[inline] +pub fn write(wr: W, value: V) -> io::Result { + value.write(wr) +} + +pub trait Floating { + fn write(self, W) -> io::Result; +} + +impl Floating for f32 { + fn write(self, wr: W) -> io::Result { + dtoa! { + floating_type: f32, + significand_type: u32, + exponent_type: i32, + + diy_significand_size: 32, + significand_size: 23, + exponent_bias: 0x7F, + mask_type: u32, + exponent_mask: 0x7F800000, + significand_mask: 0x007FFFFF, + hidden_bit: 0x00800000, + cached_powers_f: CACHED_POWERS_F_32, + cached_powers_e: CACHED_POWERS_E_32, + min_power: (-36), + }; + unsafe { dtoa(wr, self) } + } +} + +impl Floating for f64 { + fn write(self, wr: W) -> io::Result { + dtoa! { + floating_type: f64, + significand_type: u64, + exponent_type: isize, + + diy_significand_size: 64, + significand_size: 52, + exponent_bias: 0x3FF, + mask_type: u64, + exponent_mask: 0x7FF0000000000000, + significand_mask: 0x000FFFFFFFFFFFFF, + hidden_bit: 0x0010000000000000, + cached_powers_f: CACHED_POWERS_F_64, + cached_powers_e: CACHED_POWERS_E_64, + min_power: (-348), + }; + unsafe { dtoa(wr, self) } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +const MAX_DECIMAL_PLACES: isize = 324; + +static DEC_DIGITS_LUT: &'static [u8] = + b"0001020304050607080910111213141516171819\ + 2021222324252627282930313233343536373839\ + 4041424344454647484950515253545556575859\ + 6061626364656667686970717273747576777879\ + 8081828384858687888990919293949596979899"; + +// 10^-36, 10^-28, ..., 10^52 +static CACHED_POWERS_F_32: [u32; 12] = [ + 0xaa242499, 0xfd87b5f3, 0xbce50865, 0x8cbccc09, + 0xd1b71759, 0x9c400000, 0xe8d4a510, 0xad78ebc6, + 0x813f3979, 0xc097ce7c, 0x8f7e32ce, 0xd5d238a5, +]; + +static CACHED_POWERS_E_32: [i16; 12] = [ + -151, -125, -98, -71, -45, -18, 8, 35, 62, 88, 115, 141, +]; + +// 10^-348, 10^-340, ..., 10^340 +static CACHED_POWERS_F_64: [u64; 87] = [ + 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, + 0x8b16fb203055ac76, 0xcf42894a5dce35ea, + 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, + 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, + 0xbe5691ef416bd60c, 0x8dd01fad907ffc3c, + 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, + 0xea9c227723ee8bcb, 0xaecc49914078536d, + 0x823c12795db6ce57, 0xc21094364dfb5637, + 0x9096ea6f3848984f, 0xd77485cb25823ac7, + 0xa086cfcd97bf97f4, 0xef340a98172aace5, + 0xb23867fb2a35b28e, 0x84c8d4dfd2c63f3b, + 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, + 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, + 0xf3e2f893dec3f126, 0xb5b5ada8aaff80b8, + 0x87625f056c7c4a8b, 0xc9bcff6034c13053, + 0x964e858c91ba2655, 0xdff9772470297ebd, + 0xa6dfbd9fb8e5b88f, 0xf8a95fcf88747d94, + 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, + 0xcdb02555653131b6, 0x993fe2c6d07b7fac, + 0xe45c10c42a2b3b06, 0xaa242499697392d3, + 0xfd87b5f28300ca0e, 0xbce5086492111aeb, + 0x8cbccc096f5088cc, 0xd1b71758e219652c, + 0x9c40000000000000, 0xe8d4a51000000000, + 0xad78ebc5ac620000, 0x813f3978f8940984, + 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, + 0xd5d238a4abe98068, 0x9f4f2726179a2245, + 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, + 0x83c7088e1aab65db, 0xc45d1df942711d9a, + 0x924d692ca61be758, 0xda01ee641a708dea, + 0xa26da3999aef774a, 0xf209787bb47d6b85, + 0xb454e4a179dd1877, 0x865b86925b9bc5c2, + 0xc83553c5c8965d3d, 0x952ab45cfa97a0b3, + 0xde469fbd99a05fe3, 0xa59bc234db398c25, + 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, + 0x88fcf317f22241e2, 0xcc20ce9bd35c78a5, + 0x98165af37b2153df, 0xe2a0b5dc971f303a, + 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, + 0xbb764c4ca7a44410, 0x8bab8eefb6409c1a, + 0xd01fef10a657842c, 0x9b10a4e5e9913129, + 0xe7109bfba19c0c9d, 0xac2820d9623bf429, + 0x80444b5e7aa7cf85, 0xbf21e44003acdd2d, + 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, + 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, + 0xaf87023b9bf0ee6b, +]; +static CACHED_POWERS_E_64: [i16; 87] = [ + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, + -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, + -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, + -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, + -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, + 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, + 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, + 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, + 907, 933, 960, 986, 1013, 1039, 1066, +]; diff --git a/dtoa-0.4.2/tests/test.rs b/dtoa-0.4.2/tests/test.rs new file mode 100644 index 000000000..4f92d7ee1 --- /dev/null +++ b/dtoa-0.4.2/tests/test.rs @@ -0,0 +1,38 @@ +extern crate dtoa; + +use std::str; + +#[test] +fn test_f64() { + test_write(1.234e20f64, "123400000000000000000.0"); + test_write(1.234e21f64, "1.234e21"); + test_write(2.71828f64, "2.71828"); + test_write(0.0f64, "0.0"); + test_write(-0.0f64, "-0.0"); + test_write(1.1e128f64, "1.1e128"); + test_write(1.1e-64f64, "1.1e-64"); + test_write(2.718281828459045f64, "2.718281828459045"); + test_write(5e-324f64, "5e-324"); + test_write(::std::f64::MAX, "1.7976931348623157e308"); +} + +#[test] +fn test_f32() { + test_write(1.234e20f32, "123400000000000000000.0"); + test_write(1.234e21f32, "1.234e21"); + test_write(2.71828f32, "2.71828"); + test_write(0.0f32, "0.0"); + test_write(-0.0f32, "-0.0"); + test_write(1.1e32f32, "1.1e32"); + test_write(1.1e-32f32, "1.1e-32"); + test_write(2.7182817f32, "2.7182817"); + test_write(1e-45f32, "1e-45"); + test_write(::std::f32::MAX, "3.4028235e38"); +} + +fn test_write(value: F, expected: &'static str) { + let mut buf = [b'\0'; 30]; + let len = dtoa::write(&mut buf[..], value).unwrap(); + let result = str::from_utf8(&buf[..len]).unwrap(); + assert_eq!(result, expected.to_string()); +} diff --git a/env_logger-0.4.3/.cargo-checksum.json b/env_logger-0.4.3/.cargo-checksum.json new file mode 100644 index 000000000..79ae0b1f8 --- /dev/null +++ b/env_logger-0.4.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"} \ No newline at end of file diff --git a/env_logger-0.4.3/Cargo.toml b/env_logger-0.4.3/Cargo.toml new file mode 100644 index 000000000..4ac3e2e37 --- /dev/null +++ b/env_logger-0.4.3/Cargo.toml @@ -0,0 +1,35 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "env_logger" +version = "0.4.3" +authors = ["The Rust Project Developers"] +description = "A logging implementation for `log` which is configured via an environment\nvariable.\n" +homepage = "https://github.com/rust-lang/log" +documentation = "http://doc.rust-lang.org/log/env_logger" +categories = ["development-tools::debugging"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang/log" + +[[test]] +name = "regexp_filter" +harness = false +[dependencies.regex] +version = "0.2" +optional = true + +[dependencies.log] +version = "0.3" + +[features] +default = ["regex"] diff --git a/env_logger-0.4.3/LICENSE-APACHE b/env_logger-0.4.3/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/env_logger-0.4.3/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/env_logger-0.4.3/LICENSE-MIT b/env_logger-0.4.3/LICENSE-MIT new file mode 100644 index 000000000..39d4bdb5a --- /dev/null +++ b/env_logger-0.4.3/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/env_logger-0.4.3/src/lib.rs b/env_logger-0.4.3/src/lib.rs new file mode 100644 index 000000000..7e2f9da7e --- /dev/null +++ b/env_logger-0.4.3/src/lib.rs @@ -0,0 +1,652 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A logger configured via an environment variable which writes to standard +//! error. +//! +//! ## Example +//! +//! ``` +//! #[macro_use] extern crate log; +//! extern crate env_logger; +//! +//! use log::LogLevel; +//! +//! fn main() { +//! env_logger::init().unwrap(); +//! +//! debug!("this is a debug {}", "message"); +//! error!("this is printed by default"); +//! +//! if log_enabled!(LogLevel::Info) { +//! let x = 3 * 4; // expensive computation +//! info!("the answer was: {}", x); +//! } +//! } +//! ``` +//! +//! Assumes the binary is `main`: +//! +//! ```{.bash} +//! $ RUST_LOG=error ./main +//! ERROR:main: this is printed by default +//! ``` +//! +//! ```{.bash} +//! $ RUST_LOG=info ./main +//! ERROR:main: this is printed by default +//! INFO:main: the answer was: 12 +//! ``` +//! +//! ```{.bash} +//! $ RUST_LOG=debug ./main +//! DEBUG:main: this is a debug message +//! ERROR:main: this is printed by default +//! INFO:main: the answer was: 12 +//! ``` +//! +//! You can also set the log level on a per module basis: +//! +//! ```{.bash} +//! $ RUST_LOG=main=info ./main +//! ERROR:main: this is printed by default +//! INFO:main: the answer was: 12 +//! ``` +//! +//! And enable all logging: +//! +//! ```{.bash} +//! $ RUST_LOG=main ./main +//! DEBUG:main: this is a debug message +//! ERROR:main: this is printed by default +//! INFO:main: the answer was: 12 +//! ``` +//! +//! See the documentation for the log crate for more information about its API. +//! +//! ## Enabling logging +//! +//! Log levels are controlled on a per-module basis, and by default all logging +//! is disabled except for `error!`. Logging is controlled via the `RUST_LOG` +//! environment variable. The value of this environment variable is a +//! comma-separated list of logging directives. A logging directive is of the +//! form: +//! +//! ```text +//! path::to::module=log_level +//! ``` +//! +//! The path to the module is rooted in the name of the crate it was compiled +//! for, so if your program is contained in a file `hello.rs`, for example, to +//! turn on logging for this file you would use a value of `RUST_LOG=hello`. +//! Furthermore, this path is a prefix-search, so all modules nested in the +//! specified module will also have logging enabled. +//! +//! The actual `log_level` is optional to specify. If omitted, all logging will +//! be enabled. If specified, it must be one of the strings `debug`, `error`, +//! `info`, `warn`, or `trace`. +//! +//! As the log level for a module is optional, the module to enable logging for +//! is also optional. If only a `log_level` is provided, then the global log +//! level for all modules is set to this value. +//! +//! Some examples of valid values of `RUST_LOG` are: +//! +//! * `hello` turns on all logging for the 'hello' module +//! * `info` turns on all info logging +//! * `hello=debug` turns on debug logging for 'hello' +//! * `hello,std::option` turns on hello, and std's option logging +//! * `error,hello=warn` turn on global error logging and also warn for hello +//! +//! ## Filtering results +//! +//! A RUST_LOG directive may include a regex filter. The syntax is to append `/` +//! followed by a regex. Each message is checked against the regex, and is only +//! logged if it matches. Note that the matching is done after formatting the +//! log string but before adding any logging meta-data. There is a single filter +//! for all modules. +//! +//! Some examples: +//! +//! * `hello/foo` turns on all logging for the 'hello' module where the log +//! message includes 'foo'. +//! * `info/f.o` turns on all info logging where the log message includes 'foo', +//! 'f1o', 'fao', etc. +//! * `hello=debug/foo*foo` turns on debug logging for 'hello' where the log +//! message includes 'foofoo' or 'fofoo' or 'fooooooofoo', etc. +//! * `error,hello=warn/[0-9] scopes` turn on global error logging and also +//! warn for hello. In both cases the log message must include a single digit +//! number followed by 'scopes'. + +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/env_logger/")] +#![cfg_attr(test, deny(warnings))] + +// When compiled for the rustc compiler itself we want to make sure that this is +// an unstable crate +#![cfg_attr(rustbuild, feature(staged_api, rustc_private))] +#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] + +extern crate log; + +use std::env; +use std::io::prelude::*; +use std::io; +use std::mem; + +use log::{Log, LogLevel, LogLevelFilter, LogRecord, SetLoggerError, LogMetadata}; + +#[cfg(feature = "regex")] +#[path = "regex.rs"] +mod filter; + +#[cfg(not(feature = "regex"))] +#[path = "string.rs"] +mod filter; + +/// Log target, either stdout or stderr. +#[derive(Debug)] +pub enum LogTarget { + Stdout, + Stderr, +} + +/// The logger. +pub struct Logger { + directives: Vec, + filter: Option, + format: Box String + Sync + Send>, + target: LogTarget, +} + +/// LogBuilder acts as builder for initializing the Logger. +/// It can be used to customize the log format, change the enviromental variable used +/// to provide the logging directives and also set the default log level filter. +/// +/// ## Example +/// +/// ``` +/// #[macro_use] +/// extern crate log; +/// extern crate env_logger; +/// +/// use std::env; +/// use log::{LogRecord, LogLevelFilter}; +/// use env_logger::LogBuilder; +/// +/// fn main() { +/// let format = |record: &LogRecord| { +/// format!("{} - {}", record.level(), record.args()) +/// }; +/// +/// let mut builder = LogBuilder::new(); +/// builder.format(format).filter(None, LogLevelFilter::Info); +/// +/// if env::var("RUST_LOG").is_ok() { +/// builder.parse(&env::var("RUST_LOG").unwrap()); +/// } +/// +/// builder.init().unwrap(); +/// +/// error!("error message"); +/// info!("info message"); +/// } +/// ``` +pub struct LogBuilder { + directives: Vec, + filter: Option, + format: Box String + Sync + Send>, + target: LogTarget, +} + +impl LogBuilder { + /// Initializes the log builder with defaults + pub fn new() -> LogBuilder { + LogBuilder { + directives: Vec::new(), + filter: None, + format: Box::new(|record: &LogRecord| { + format!("{}:{}: {}", record.level(), + record.location().module_path(), record.args()) + }), + target: LogTarget::Stderr, + } + } + + /// Adds filters to the logger + /// + /// The given module (if any) will log at most the specified level provided. + /// If no module is provided then the filter will apply to all log messages. + pub fn filter(&mut self, + module: Option<&str>, + level: LogLevelFilter) -> &mut Self { + self.directives.push(LogDirective { + name: module.map(|s| s.to_string()), + level: level, + }); + self + } + + /// Sets the format function for formatting the log output. + /// + /// This function is called on each record logged to produce a string which + /// is actually printed out. + pub fn format(&mut self, format: F) -> &mut Self + where F: Fn(&LogRecord) -> String + Sync + Send + { + self.format = Box::new(format); + self + } + + /// Sets the target for the log output. + /// + /// Env logger can log to either stdout or stderr. The default is stderr. + pub fn target(&mut self, target: LogTarget) -> &mut Self { + self.target = target; + self + } + + /// Parses the directives string in the same form as the RUST_LOG + /// environment variable. + /// + /// See the module documentation for more details. + pub fn parse(&mut self, filters: &str) -> &mut Self { + let (directives, filter) = parse_logging_spec(filters); + + self.filter = filter; + + for directive in directives { + self.directives.push(directive); + } + self + } + + /// Initializes the global logger with an env logger. + /// + /// This should be called early in the execution of a Rust program, and the + /// global logger may only be initialized once. Future initialization + /// attempts will return an error. + pub fn init(&mut self) -> Result<(), SetLoggerError> { + log::set_logger(|max_level| { + let logger = self.build(); + max_level.set(logger.filter()); + Box::new(logger) + }) + } + + /// Build an env logger. + pub fn build(&mut self) -> Logger { + if self.directives.is_empty() { + // Adds the default filter if none exist + self.directives.push(LogDirective { + name: None, + level: LogLevelFilter::Error, + }); + } else { + // Sort the directives by length of their name, this allows a + // little more efficient lookup at runtime. + self.directives.sort_by(|a, b| { + let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0); + let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0); + alen.cmp(&blen) + }); + } + + Logger { + directives: mem::replace(&mut self.directives, Vec::new()), + filter: mem::replace(&mut self.filter, None), + format: mem::replace(&mut self.format, Box::new(|_| String::new())), + target: mem::replace(&mut self.target, LogTarget::Stderr), + } + } +} + +impl Logger { + pub fn new() -> Logger { + let mut builder = LogBuilder::new(); + + if let Ok(s) = env::var("RUST_LOG") { + builder.parse(&s); + } + + builder.build() + } + + pub fn filter(&self) -> LogLevelFilter { + self.directives.iter() + .map(|d| d.level).max() + .unwrap_or(LogLevelFilter::Off) + } + + fn enabled(&self, level: LogLevel, target: &str) -> bool { + // Search for the longest match, the vector is assumed to be pre-sorted. + for directive in self.directives.iter().rev() { + match directive.name { + Some(ref name) if !target.starts_with(&**name) => {}, + Some(..) | None => { + return level <= directive.level + } + } + } + false + } +} + +impl Log for Logger { + fn enabled(&self, metadata: &LogMetadata) -> bool { + self.enabled(metadata.level(), metadata.target()) + } + + fn log(&self, record: &LogRecord) { + if !Log::enabled(self, record.metadata()) { + return; + } + + if let Some(filter) = self.filter.as_ref() { + if !filter.is_match(&*record.args().to_string()) { + return; + } + } + + match self.target { + LogTarget::Stdout => println!("{}", (self.format)(record)), + LogTarget::Stderr => { + let _ = writeln!(&mut io::stderr(), "{}", (self.format)(record)); + }, + }; + } +} + +struct LogDirective { + name: Option, + level: LogLevelFilter, +} + +/// Initializes the global logger with an env logger. +/// +/// This should be called early in the execution of a Rust program, and the +/// global logger may only be initialized once. Future initialization attempts +/// will return an error. +pub fn init() -> Result<(), SetLoggerError> { + let mut builder = LogBuilder::new(); + + if let Ok(s) = env::var("RUST_LOG") { + builder.parse(&s); + } + + builder.init() +} + +/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=error/foo") +/// and return a vector with log directives. +fn parse_logging_spec(spec: &str) -> (Vec, Option) { + let mut dirs = Vec::new(); + + let mut parts = spec.split('/'); + let mods = parts.next(); + let filter = parts.next(); + if parts.next().is_some() { + println!("warning: invalid logging spec '{}', \ + ignoring it (too many '/'s)", spec); + return (dirs, None); + } + mods.map(|m| { for s in m.split(',') { + if s.len() == 0 { continue } + let mut parts = s.split('='); + let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) { + (Some(part0), None, None) => { + // if the single argument is a log-level string or number, + // treat that as a global fallback + match part0.parse() { + Ok(num) => (num, None), + Err(_) => (LogLevelFilter::max(), Some(part0)), + } + } + (Some(part0), Some(""), None) => (LogLevelFilter::max(), Some(part0)), + (Some(part0), Some(part1), None) => { + match part1.parse() { + Ok(num) => (num, Some(part0)), + _ => { + println!("warning: invalid logging spec '{}', \ + ignoring it", part1); + continue + } + } + }, + _ => { + println!("warning: invalid logging spec '{}', \ + ignoring it", s); + continue + } + }; + dirs.push(LogDirective { + name: name.map(|s| s.to_string()), + level: log_level, + }); + }}); + + let filter = filter.map_or(None, |filter| { + match filter::Filter::new(filter) { + Ok(re) => Some(re), + Err(e) => { + println!("warning: invalid regex filter - {}", e); + None + } + } + }); + + return (dirs, filter); +} + +#[cfg(test)] +mod tests { + use log::{LogLevel, LogLevelFilter}; + + use super::{LogBuilder, Logger, LogDirective, parse_logging_spec}; + + fn make_logger(dirs: Vec) -> Logger { + let mut logger = LogBuilder::new().build(); + logger.directives = dirs; + logger + } + + #[test] + fn filter_info() { + let logger = LogBuilder::new().filter(None, LogLevelFilter::Info).build(); + assert!(logger.enabled(LogLevel::Info, "crate1")); + assert!(!logger.enabled(LogLevel::Debug, "crate1")); + } + + #[test] + fn filter_beginning_longest_match() { + let logger = LogBuilder::new() + .filter(Some("crate2"), LogLevelFilter::Info) + .filter(Some("crate2::mod"), LogLevelFilter::Debug) + .filter(Some("crate1::mod1"), LogLevelFilter::Warn) + .build(); + assert!(logger.enabled(LogLevel::Debug, "crate2::mod1")); + assert!(!logger.enabled(LogLevel::Debug, "crate2")); + } + + #[test] + fn parse_default() { + let logger = LogBuilder::new().parse("info,crate1::mod1=warn").build(); + assert!(logger.enabled(LogLevel::Warn, "crate1::mod1")); + assert!(logger.enabled(LogLevel::Info, "crate2::mod2")); + } + + #[test] + fn match_full_path() { + let logger = make_logger(vec![ + LogDirective { + name: Some("crate2".to_string()), + level: LogLevelFilter::Info + }, + LogDirective { + name: Some("crate1::mod1".to_string()), + level: LogLevelFilter::Warn + } + ]); + assert!(logger.enabled(LogLevel::Warn, "crate1::mod1")); + assert!(!logger.enabled(LogLevel::Info, "crate1::mod1")); + assert!(logger.enabled(LogLevel::Info, "crate2")); + assert!(!logger.enabled(LogLevel::Debug, "crate2")); + } + + #[test] + fn no_match() { + let logger = make_logger(vec![ + LogDirective { name: Some("crate2".to_string()), level: LogLevelFilter::Info }, + LogDirective { name: Some("crate1::mod1".to_string()), level: LogLevelFilter::Warn } + ]); + assert!(!logger.enabled(LogLevel::Warn, "crate3")); + } + + #[test] + fn match_beginning() { + let logger = make_logger(vec![ + LogDirective { name: Some("crate2".to_string()), level: LogLevelFilter::Info }, + LogDirective { name: Some("crate1::mod1".to_string()), level: LogLevelFilter::Warn } + ]); + assert!(logger.enabled(LogLevel::Info, "crate2::mod1")); + } + + #[test] + fn match_beginning_longest_match() { + let logger = make_logger(vec![ + LogDirective { name: Some("crate2".to_string()), level: LogLevelFilter::Info }, + LogDirective { name: Some("crate2::mod".to_string()), level: LogLevelFilter::Debug }, + LogDirective { name: Some("crate1::mod1".to_string()), level: LogLevelFilter::Warn } + ]); + assert!(logger.enabled(LogLevel::Debug, "crate2::mod1")); + assert!(!logger.enabled(LogLevel::Debug, "crate2")); + } + + #[test] + fn match_default() { + let logger = make_logger(vec![ + LogDirective { name: None, level: LogLevelFilter::Info }, + LogDirective { name: Some("crate1::mod1".to_string()), level: LogLevelFilter::Warn } + ]); + assert!(logger.enabled(LogLevel::Warn, "crate1::mod1")); + assert!(logger.enabled(LogLevel::Info, "crate2::mod2")); + } + + #[test] + fn zero_level() { + let logger = make_logger(vec![ + LogDirective { name: None, level: LogLevelFilter::Info }, + LogDirective { name: Some("crate1::mod1".to_string()), level: LogLevelFilter::Off } + ]); + assert!(!logger.enabled(LogLevel::Error, "crate1::mod1")); + assert!(logger.enabled(LogLevel::Info, "crate2::mod2")); + } + + #[test] + fn parse_logging_spec_valid() { + let (dirs, filter) = parse_logging_spec("crate1::mod1=error,crate1::mod2,crate2=debug"); + assert_eq!(dirs.len(), 3); + assert_eq!(dirs[0].name, Some("crate1::mod1".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::Error); + + assert_eq!(dirs[1].name, Some("crate1::mod2".to_string())); + assert_eq!(dirs[1].level, LogLevelFilter::max()); + + assert_eq!(dirs[2].name, Some("crate2".to_string())); + assert_eq!(dirs[2].level, LogLevelFilter::Debug); + assert!(filter.is_none()); + } + + #[test] + fn parse_logging_spec_invalid_crate() { + // test parse_logging_spec with multiple = in specification + let (dirs, filter) = parse_logging_spec("crate1::mod1=warn=info,crate2=debug"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::Debug); + assert!(filter.is_none()); + } + + #[test] + fn parse_logging_spec_invalid_log_level() { + // test parse_logging_spec with 'noNumber' as log level + let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=debug"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::Debug); + assert!(filter.is_none()); + } + + #[test] + fn parse_logging_spec_string_log_level() { + // test parse_logging_spec with 'warn' as log level + let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::Warn); + assert!(filter.is_none()); + } + + #[test] + fn parse_logging_spec_empty_log_level() { + // test parse_logging_spec with '' as log level + let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2="); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::max()); + assert!(filter.is_none()); + } + + #[test] + fn parse_logging_spec_global() { + // test parse_logging_spec with no crate + let (dirs, filter) = parse_logging_spec("warn,crate2=debug"); + assert_eq!(dirs.len(), 2); + assert_eq!(dirs[0].name, None); + assert_eq!(dirs[0].level, LogLevelFilter::Warn); + assert_eq!(dirs[1].name, Some("crate2".to_string())); + assert_eq!(dirs[1].level, LogLevelFilter::Debug); + assert!(filter.is_none()); + } + + #[test] + fn parse_logging_spec_valid_filter() { + let (dirs, filter) = parse_logging_spec("crate1::mod1=error,crate1::mod2,crate2=debug/abc"); + assert_eq!(dirs.len(), 3); + assert_eq!(dirs[0].name, Some("crate1::mod1".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::Error); + + assert_eq!(dirs[1].name, Some("crate1::mod2".to_string())); + assert_eq!(dirs[1].level, LogLevelFilter::max()); + + assert_eq!(dirs[2].name, Some("crate2".to_string())); + assert_eq!(dirs[2].level, LogLevelFilter::Debug); + assert!(filter.is_some() && filter.unwrap().to_string() == "abc"); + } + + #[test] + fn parse_logging_spec_invalid_crate_filter() { + let (dirs, filter) = parse_logging_spec("crate1::mod1=error=warn,crate2=debug/a.c"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate2".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::Debug); + assert!(filter.is_some() && filter.unwrap().to_string() == "a.c"); + } + + #[test] + fn parse_logging_spec_empty_with_filter() { + let (dirs, filter) = parse_logging_spec("crate1/a*c"); + assert_eq!(dirs.len(), 1); + assert_eq!(dirs[0].name, Some("crate1".to_string())); + assert_eq!(dirs[0].level, LogLevelFilter::max()); + assert!(filter.is_some() && filter.unwrap().to_string() == "a*c"); + } +} diff --git a/env_logger-0.4.3/src/regex.rs b/env_logger-0.4.3/src/regex.rs new file mode 100644 index 000000000..0df03e673 --- /dev/null +++ b/env_logger-0.4.3/src/regex.rs @@ -0,0 +1,28 @@ +extern crate regex; + +use std::fmt; + +use self::regex::Regex; + +pub struct Filter { + inner: Regex, +} + +impl Filter { + pub fn new(spec: &str) -> Result { + match Regex::new(spec){ + Ok(r) => Ok(Filter { inner: r }), + Err(e) => Err(e.to_string()), + } + } + + pub fn is_match(&self, s: &str) -> bool { + self.inner.is_match(s) + } +} + +impl fmt::Display for Filter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} diff --git a/env_logger-0.4.3/src/string.rs b/env_logger-0.4.3/src/string.rs new file mode 100644 index 000000000..74d0e04db --- /dev/null +++ b/env_logger-0.4.3/src/string.rs @@ -0,0 +1,21 @@ +use std::fmt; + +pub struct Filter { + inner: String, +} + +impl Filter { + pub fn new(spec: &str) -> Result { + Ok(Filter { inner: spec.to_string() }) + } + + pub fn is_match(&self, s: &str) -> bool { + s.contains(&self.inner) + } +} + +impl fmt::Display for Filter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} diff --git a/env_logger-0.4.3/tests/regexp_filter.rs b/env_logger-0.4.3/tests/regexp_filter.rs new file mode 100644 index 000000000..5036fb8e3 --- /dev/null +++ b/env_logger-0.4.3/tests/regexp_filter.rs @@ -0,0 +1,51 @@ +#[macro_use] extern crate log; +extern crate env_logger; + +use std::process; +use std::env; +use std::str; + +fn main() { + if env::var("LOG_REGEXP_TEST").ok() == Some(String::from("1")) { + child_main(); + } else { + parent_main() + } +} + +fn child_main() { + env_logger::init().unwrap(); + info!("XYZ Message"); +} + +fn run_child(rust_log: String) -> bool { + let exe = env::current_exe().unwrap(); + let out = process::Command::new(exe) + .env("LOG_REGEXP_TEST", "1") + .env("RUST_LOG", rust_log) + .output() + .unwrap_or_else(|e| panic!("Unable to start child process: {}", e)); + str::from_utf8(out.stderr.as_ref()).unwrap().contains("XYZ Message") +} + +fn assert_message_printed(rust_log: &str) { + if !run_child(rust_log.to_string()) { + panic!("RUST_LOG={} should allow the test log message", rust_log) + } +} + +fn assert_message_not_printed(rust_log: &str) { + if run_child(rust_log.to_string()) { + panic!("RUST_LOG={} should not allow the test log message", rust_log) + } +} + +fn parent_main() { + // test normal log severity levels + assert_message_printed("info"); + assert_message_not_printed("warn"); + + // test of regular expression filters + assert_message_printed("info/XYZ"); + assert_message_not_printed("info/XXX"); +} diff --git a/error-chain-0.11.0/.cargo-checksum.json b/error-chain-0.11.0/.cargo-checksum.json new file mode 100644 index 000000000..d961353eb --- /dev/null +++ b/error-chain-0.11.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"} \ No newline at end of file diff --git a/error-chain-0.11.0/.travis.yml b/error-chain-0.11.0/.travis.yml new file mode 100644 index 000000000..6bbf37eb3 --- /dev/null +++ b/error-chain-0.11.0/.travis.yml @@ -0,0 +1,46 @@ +language: rust +rust: +- stable +- beta +- nightly +# Oldest supported version for all features. +# Use of https://github.com/rust-lang/rfcs/pull/16 +- 1.14.0 +# Oldest supported version as dependency, with no features, tests, or examples. +- 1.10.0 + +sudo: false +cache: cargo +addons: + apt: + packages: + - libcurl4-openssl-dev + - libelf-dev + - libdw-dev + +before_script: +- | + pip install 'travis-cargo<0.2' --user && + export PATH=$HOME/.local/bin:$PATH + +script: +- travis-cargo build -- $FEATURES +- travis-cargo --skip 1.10.0 test -- $FEATURES + +after_success: +- travis-cargo --only stable doc +- travis-cargo --only stable doc-upload + +env: + global: + - secure: ncxJbvJM1vCZfcEftjsFKJMxxhKLgWKaR8Go9AMo0VB5fB2XVW/6NYO5bQEEYpOf1Nc/+2FbI2+Dkz0S/mJpUcNSfBgablCHgwU2sHse7KsoaqfHj2mf1E3exjzSHoP96hPGicC5zAjSXFjCgJPOUSGqqRaJ7z5AsJLhJT6LuK7QpvwPBZzklUN8T+n1sVmws8TNmRIbaniq/q6wYHANHcy6Dl59dx4sKwniUGiZdUhCiddVpoxbECSxc0A8mN2pk7/aW+WGxK3goBs5ZF7+JXF318F62pDcXQmR5CX6WdpenIcJ25g1Vg1WhQ4Ifpe17CN0bfxV8ShuzrQUThCDMffZCo9XySBtODdEowwK1UIpjnFLfIxjOs45Cd8o3tM2j0CfvtnjOz6BCdUU0qiwNPPNx0wFkx3ZiOfSh+FhBhvyPM12HN2tdN0esgVBItFmEci+sSIIXqjVL6DNiu5zTjbu0bs6COwlUWdmL6vmsZtq5tl7Cno9+C3szxRVAkShGydd04l9NYjqNEzTa1EPG50OsnVRKGdRiFzSxhc3BWExNKvcQ4v867t6/PpPkW6s4oXmYI3+De+8O7ExWc6a4alcrDXKlMs5fCb5Pcd4Ju9kowcjkoJo5yf2wW3Ox5R8SJpaEEpvyhx5O/qtIxjhHNzeo8Wsr/6gdNDv20r91TI= + - TRAVIS_CARGO_NIGHTLY_FEATURE="" + - RUSTFLAGS="-D warnings" + matrix: + - FEATURES=--features=backtrace + - FEATURES=--no-default-features + +matrix: + exclude: + - env: FEATURES=--features=backtrace + rust: 1.10.0 diff --git a/error-chain-0.11.0/CHANGELOG.md b/error-chain-0.11.0/CHANGELOG.md new file mode 100644 index 000000000..ed0f12e3a --- /dev/null +++ b/error-chain-0.11.0/CHANGELOG.md @@ -0,0 +1,120 @@ +# Unreleased + +# 0.11.0 + +- Change last rust version supported to 1.14 +- [Cache whether RUST_BACKTRACE is enabled in a relaxed atomic static.](https://github.com/rust-lang-nursery/error-chain/pull/210) +- [Mask the `quick_error` macro from the doc](https://github.com/rust-lang-nursery/error-chain/pull/210) +- [Make generated `ErrorKind` enums non-exhaustive](https://github.com/rust-lang-nursery/error-chain/pull/193) +- All 0.11.0-rc.2 changes + +# 0.11.0-rc.2 + +- [Make `ErrorChainIter`'s field private](https://github.com/rust-lang-nursery/error-chain/issues/178) +- [Rename `ErrorChainIter` to `Iter`](https://github.com/rust-lang-nursery/error-chain/issues/168) +- [Implement `Debug` for `ErrorChainIter`](https://github.com/rust-lang-nursery/error-chain/issues/169) +- [Rename `ChainedError::display` to `display_chain`](https://github.com/rust-lang-nursery/error-chain/issues/180) +- [Add a new method for `Error`: `chain_err`.](https://github.com/rust-lang-nursery/error-chain/pull/141) +- [Allow `chain_err` to be used on `Option`](https://github.com/rust-lang-nursery/error-chain/pull/156) +- [Add support for creating an error chain on boxed trait errors (`Box`)](https://github.com/rust-lang-nursery/error-chain/pull/156) +- [Remove lint for unused doc comment.](https://github.com/rust-lang-nursery/error-chain/pull/199) +- [Hide error_chain_processed macro from documentation.](https://github.com/rust-lang-nursery/error-chain/pull/212) + +# 0.10.0 + +- [Add a new constructor for `Error`: `with_chain`.](https://github.com/rust-lang-nursery/error-chain/pull/126) +- [Add the `ensure!` macro.](https://github.com/rust-lang-nursery/error-chain/pull/135) + +# 0.9.0 + +- Revert [Add a `Sync` bound to errors](https://github.com/rust-lang-nursery/error-chain/pull/110) + +# 0.8.1 + +- Add crates.io category. + +# 0.8.0 + +- [Add a `Sync` bound to errors](https://github.com/rust-lang-nursery/error-chain/pull/110) +- [Add `ChainedError::display` to format error chains](https://github.com/rust-lang-nursery/error-chain/pull/113) + +# 0.7.2 + +- Add `quick_main!` (#88). +- `allow(unused)` for the `Result` wrapper. +- Minimum rust version supported is now 1.10 on some conditions (#103). + +# 0.7.1 + +- [Add the `bail!` macro](https://github.com/rust-lang-nursery/error-chain/pull/76) + +# 0.7.0 + +- [Rollback several design changes to fix regressions](https://github.com/rust-lang-nursery/error-chain/pull/75) +- New `Variant(Error) #[attrs]` for `links` and `foreign_links`. +- Hide implementation details from the doc. +- Always generate `Error::backtrace`. + +# 0.6.2 + +- Allow dead code. + +# 0.6.1 + +- Fix wrong trait constraint in ResultExt implementation (#66). + +# 0.6.0 + +- Conditional compilation for error variants. +- Backtrace generation is now a feature. +- More standard trait implementations for extra convenience. +- Remove ChainErr. +- Remove need to specify `ErrorKind` in `links {}`. +- Add ResultExt trait. +- Error.1 is a struct instead of a tuple. +- Error is now a struct. +- The declarations order is more flexible. +- Way better error reporting when there is a syntax error in the macro call. +- `Result` generation can be disabled. +- At most one declaration of each type can be present. + +# 0.5.0 + +- [Only generate backtraces with RUST_BACKTRACE set](https://github.com/rust-lang-nursery/error-chain/pull/27) +- [Fixup matching, disallow repeating "types" section](https://github.com/rust-lang-nursery/error-chain/pull/26) +- [Fix tests on stable/beta](https://github.com/rust-lang-nursery/error-chain/pull/28) +- [Only deploy docs when tagged](https://github.com/rust-lang-nursery/error-chain/pull/30) + +Contributors: benaryorg, Brian Anderson, Georg Brandl + +# 0.4.2 + +- [Fix the resolution of the ErrorKind description method](https://github.com/rust-lang-nursery/error-chain/pull/24) + +Contributors: Brian Anderson + +# 0.4.1 (yanked) + +- [Fix a problem with resolving methods of the standard Error type](https://github.com/rust-lang-nursery/error-chain/pull/22) + +Contributors: Brian Anderson + +# 0.4.0 (yanked) + +- [Remove the foreign link description and forward to the foreign error](https://github.com/rust-lang-nursery/error-chain/pull/19) +- [Allow missing sections](https://github.com/rust-lang-nursery/error-chain/pull/17) + +Contributors: Brian Anderson, Taylor Cramer + +# 0.3.0 + +- [Forward Display implementation for foreign errors](https://github.com/rust-lang-nursery/error-chain/pull/13) + +Contributors: Brian Anderson, Taylor Cramer + +# 0.2.2 + +- [Don't require `types` section in macro invocation](https://github.com/rust-lang-nursery/error-chain/pull/8) +- [Add "quick start" to README](https://github.com/rust-lang-nursery/error-chain/pull/9) + +Contributors: Brian Anderson, Jake Shadle, Nate Mara diff --git a/error-chain-0.11.0/Cargo.toml b/error-chain-0.11.0/Cargo.toml new file mode 100644 index 000000000..6c4e0e498 --- /dev/null +++ b/error-chain-0.11.0/Cargo.toml @@ -0,0 +1,32 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "error-chain" +version = "0.11.0" +authors = ["Brian Anderson ", "Paul Colomiets ", "Colin Kiegel ", "Yamakaky "] +description = "Yet another error boilerplate library." +documentation = "https://docs.rs/error-chain" +readme = "README.md" +keywords = ["error"] +categories = ["rust-patterns"] +license = "MIT/Apache-2.0" +repository = "https://github.com/rust-lang-nursery/error-chain" +[dependencies.backtrace] +version = "0.3" +optional = true + +[features] +example_generated = [] +default = ["backtrace", "example_generated"] +[badges.travis-ci] +repository = "rust-lang-nursery/error-chain" diff --git a/error-chain-0.11.0/LICENSE-APACHE b/error-chain-0.11.0/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/error-chain-0.11.0/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/error-chain-0.11.0/LICENSE-MIT b/error-chain-0.11.0/LICENSE-MIT new file mode 100644 index 000000000..5f28864c8 --- /dev/null +++ b/error-chain-0.11.0/LICENSE-MIT @@ -0,0 +1,26 @@ +Copyright (c) 2017 The Error-Chain Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/error-chain-0.11.0/README.md b/error-chain-0.11.0/README.md new file mode 100644 index 000000000..51e50533e --- /dev/null +++ b/error-chain-0.11.0/README.md @@ -0,0 +1,36 @@ +# error-chain - Consistent error handling for Rust + +[![Build Status](https://api.travis-ci.org/rust-lang-nursery/error-chain.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/error-chain) +[![Latest Version](https://img.shields.io/crates/v/error-chain.svg)](https://crates.io/crates/error-chain) +[![License](https://img.shields.io/github/license/rust-lang-nursery/error-chain.svg)](https://github.com/rust-lang-nursery/error-chain) + +`error-chain` makes it easy to take full advantage of Rust's error +handling features without the overhead of maintaining boilerplate +error types and conversions. It implements an opinionated strategy for +defining your own error types, as well as conversions from others' +error types. + +[Documentation (crates.io)](https://docs.rs/error-chain). + +[Documentation (master)](https://rust-lang-nursery.github.io/error-chain). + +## Quick start + +If you just want to set up your new project with error-chain, +follow the [quickstart.rs] template, and read this [intro] +to error-chain. + +[quickstart.rs]: https://github.com/rust-lang-nursery/error-chain/blob/master/examples/quickstart.rs +[intro]: http://brson.github.io/2016/11/30/starting-with-error-chain + +## Supported Rust version + +Please view the beginning of the [Travis configuration file](.travis.yml) +to see the oldest supported Rust version. + +Note that `error-chain` supports older versions of Rust when built with +`default-features = false`. + +## License + +MIT/Apache-2.0 diff --git a/error-chain-0.11.0/examples/all.rs b/error-chain-0.11.0/examples/all.rs new file mode 100644 index 000000000..ccc3ab703 --- /dev/null +++ b/error-chain-0.11.0/examples/all.rs @@ -0,0 +1,36 @@ +#[macro_use] +extern crate error_chain; + +pub mod inner { + error_chain!{} +} + +#[cfg(feature = "a_feature")] +pub mod feature { + error_chain!{} +} + +error_chain! { + // Types generated by the macro. If empty or absent, it defaults to + // Error, ErrorKind, Result; + types { + // With custom names: + MyError, MyErrorKind, MyResult; + // Without the `Result` wrapper: + // Error, ErrorKind; + } + + // Automatic bindings to other error types generated by `error_chain!`. + links { + Inner(inner::Error, inner::ErrorKind); + // Attributes can be added at the end of the declaration. + Feature(feature::Error, feature::ErrorKind) #[cfg(feature = "a_feature")]; + } + + // Bindings to types implementing std::error::Error. + foreign_links { + Io(::std::io::Error); + } +} + +fn main() {} diff --git a/error-chain-0.11.0/examples/chain_err.rs b/error-chain-0.11.0/examples/chain_err.rs new file mode 100644 index 000000000..bd8effdaf --- /dev/null +++ b/error-chain-0.11.0/examples/chain_err.rs @@ -0,0 +1,69 @@ +//! Demonstrates usage of `Error::caused` method. This method enables chaining errors +//! like `ResultExt::chain_err` but doesn't require the presence of a `Result` wrapper. + +#[macro_use] +extern crate error_chain; + +use std::fs::File; + +mod errors { + use std::io; + use super::LaunchStage; + + error_chain! { + foreign_links { + Io(io::Error) #[doc = "Error during IO"]; + } + + errors { + Launch(phase: LaunchStage) { + description("An error occurred during startup") + display("Startup aborted: {:?} did not complete successfully", phase) + } + + ConfigLoad(path: String) { + description("Config file not found") + display("Unable to read file `{}`", path) + } + } + } + + impl From for ErrorKind { + fn from(v: LaunchStage) -> Self { + ErrorKind::Launch(v) + } + } +} + +pub use errors::*; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum LaunchStage { + ConfigLoad, + ConfigParse, + ConfigResolve, +} + +/// Read the service config from the file specified. +fn load_config(rel_path: &str) -> Result<()> { + File::open(rel_path) + .map(|_| ()) + .chain_err(|| ErrorKind::ConfigLoad(rel_path.to_string())) +} + +/// Launch the service. +fn launch(rel_path: &str) -> Result<()> { + load_config(rel_path).map_err(|e| match e { + e @ Error(ErrorKind::ConfigLoad(_), _) => { + e.chain_err(|| LaunchStage::ConfigLoad) + } + e => e.chain_err(|| "Unknown failure"), + }) +} + +fn main() { + let chain = launch("does_not_exist.json").unwrap_err(); + for err in chain.iter() { + println!("{}", err); + } +} diff --git a/error-chain-0.11.0/examples/doc.rs b/error-chain-0.11.0/examples/doc.rs new file mode 100644 index 000000000..999ac9cef --- /dev/null +++ b/error-chain-0.11.0/examples/doc.rs @@ -0,0 +1,28 @@ +#![deny(missing_docs)] + +//! This module is used to check that all generated items are documented. + +#[macro_use] +extern crate error_chain; + +/// Inner module. +pub mod inner { + error_chain!{} +} + +error_chain! { + links { + Inner(inner::Error, inner::ErrorKind) #[doc = "Doc"]; + } + foreign_links { + Io(::std::io::Error) #[doc = "Io"]; + } + errors { + /// Doc + Test2 { + + } + } +} + +fn main() {} diff --git a/error-chain-0.11.0/examples/quickstart.rs b/error-chain-0.11.0/examples/quickstart.rs new file mode 100644 index 000000000..2e3e2b5d3 --- /dev/null +++ b/error-chain-0.11.0/examples/quickstart.rs @@ -0,0 +1,80 @@ +// Simple and robust error handling with error-chain! +// Use this as a template for new projects. + +// `error_chain!` can recurse deeply +#![recursion_limit = "1024"] + +// Import the macro. Don't forget to add `error-chain` in your +// `Cargo.toml`! +#[macro_use] +extern crate error_chain; + +// We'll put our errors in an `errors` module, and other modules in +// this crate will `use errors::*;` to get access to everything +// `error_chain!` creates. +mod errors { + // Create the Error, ErrorKind, ResultExt, and Result types + error_chain!{} +} + +// This only gives access within this module. Make this `pub use errors::*;` +// instead if the types must be accessible from other modules (e.g., within +// a `links` section). +use errors::*; + +fn main() { + if let Err(ref e) = run() { + use std::io::Write; + let stderr = &mut ::std::io::stderr(); + let errmsg = "Error writing to stderr"; + + writeln!(stderr, "error: {}", e).expect(errmsg); + + for e in e.iter().skip(1) { + writeln!(stderr, "caused by: {}", e).expect(errmsg); + } + + // The backtrace is not always generated. Try to run this example + // with `RUST_BACKTRACE=1`. + if let Some(backtrace) = e.backtrace() { + writeln!(stderr, "backtrace: {:?}", backtrace).expect(errmsg); + } + + ::std::process::exit(1); + } +} + +// The above main gives you maximum control over how the error is +// formatted. If you don't care (i.e. you want to display the full +// error during an assert) you can just call the `display_chain` method +// on the error object +#[allow(dead_code)] +fn alternative_main() { + if let Err(ref e) = run() { + use std::io::Write; + use error_chain::ChainedError; // trait which holds `display_chain` + let stderr = &mut ::std::io::stderr(); + let errmsg = "Error writing to stderr"; + + writeln!(stderr, "{}", e.display_chain()).expect(errmsg); + ::std::process::exit(1); + } +} + +// Use this macro to auto-generate the main above. You may want to +// set the `RUST_BACKTRACE` env variable to see a backtrace. +// quick_main!(run); + + +// Most functions will return the `Result` type, imported from the +// `errors` module. It is a typedef of the standard `Result` type +// for which the error type is always our own `Error`. +fn run() -> Result<()> { + use std::fs::File; + + // This operation will fail + File::open("tretrete") + .chain_err(|| "unable to open tretrete file")?; + + Ok(()) +} diff --git a/error-chain-0.11.0/examples/size.rs b/error-chain-0.11.0/examples/size.rs new file mode 100644 index 000000000..ae360d66e --- /dev/null +++ b/error-chain-0.11.0/examples/size.rs @@ -0,0 +1,38 @@ +#[macro_use] +extern crate error_chain; + +use std::mem::{size_of, size_of_val}; + +error_chain! { + errors { + AVariant + Another + } +} + +fn main() { + println!("Memory usage in bytes"); + println!("---------------------"); + println!("Result<()>: {}", size_of::>()); + println!(" (): {}", size_of::<()>()); + println!(" Error: {}", size_of::()); + println!(" ErrorKind: {}", size_of::()); + let msg = ErrorKind::Msg("test".into()); + println!(" ErrorKind::Msg: {}", size_of_val(&msg)); + println!(" String: {}", size_of::()); + println!(" State: {}", size_of::()); + #[cfg(feature = "backtrace")] + { + let state = error_chain::State { + next_error: None, + backtrace: None, + }; + println!(" State.next_error: {}", size_of_val(&state.next_error)); + println!(" State.backtrace: {}", size_of_val(&state.backtrace)); + } + #[cfg(not(feature = "backtrace"))] + { + let state = error_chain::State { next_error: None }; + println!(" State.next_error: {}", size_of_val(&state.next_error)); + } +} diff --git a/error-chain-0.11.0/src/bin/has_backtrace.rs b/error-chain-0.11.0/src/bin/has_backtrace.rs new file mode 100644 index 000000000..c5dac058a --- /dev/null +++ b/error-chain-0.11.0/src/bin/has_backtrace.rs @@ -0,0 +1,18 @@ +//! Exits with exit code 0 if backtraces are disabled and 1 if they are enabled. +//! Used by tests to make sure backtraces are available when they should be. Should not be used +//! outside of the tests. + +#[macro_use] +extern crate error_chain; + +error_chain! { + errors { + MyError + } +} + +fn main() { + let err = Error::from(ErrorKind::MyError); + let has_backtrace = err.backtrace().is_some(); + ::std::process::exit(has_backtrace as i32); +} diff --git a/error-chain-0.11.0/src/error_chain.rs b/error-chain-0.11.0/src/error_chain.rs new file mode 100644 index 000000000..cbd42cd67 --- /dev/null +++ b/error-chain-0.11.0/src/error_chain.rs @@ -0,0 +1,458 @@ +/// Prefer to use `error_chain` instead of this macro. +#[doc(hidden)] +#[macro_export] +macro_rules! impl_error_chain_processed { + // Default values for `types`. + ( + types {} + $( $rest: tt )* + ) => { + impl_error_chain_processed! { + types { + Error, ErrorKind, ResultExt, Result; + } + $( $rest )* + } + }; + // With `Result` wrapper. + ( + types { + $error_name:ident, $error_kind_name:ident, + $result_ext_name:ident, $result_name:ident; + } + $( $rest: tt )* + ) => { + impl_error_chain_processed! { + types { + $error_name, $error_kind_name, + $result_ext_name; + } + $( $rest )* + } + /// Convenient wrapper around `std::Result`. + #[allow(unused)] + pub type $result_name = ::std::result::Result; + }; + // Without `Result` wrapper. + ( + types { + $error_name:ident, $error_kind_name:ident, + $result_ext_name:ident; + } + + links { + $( $link_variant:ident ( $link_error_path:path, $link_kind_path:path ) + $( #[$meta_links:meta] )*; ) * + } + + foreign_links { + $( $foreign_link_variant:ident ( $foreign_link_error_path:path ) + $( #[$meta_foreign_links:meta] )*; )* + } + + errors { + $( $error_chunks:tt ) * + } + + ) => { + /// The Error type. + /// + /// This tuple struct is made of two elements: + /// + /// - an `ErrorKind` which is used to determine the type of the error. + /// - An internal `State`, not meant for direct use outside of `error_chain` + /// internals, containing: + /// - a backtrace, generated when the error is created. + /// - an error chain, used for the implementation of `Error::cause()`. + #[derive(Debug)] + pub struct $error_name( + // The members must be `pub` for `links`. + /// The kind of the error. + pub $error_kind_name, + /// Contains the error chain and the backtrace. + #[doc(hidden)] + pub $crate::State, + ); + + impl $crate::ChainedError for $error_name { + type ErrorKind = $error_kind_name; + + fn new(kind: $error_kind_name, state: $crate::State) -> $error_name { + $error_name(kind, state) + } + + fn from_kind(kind: Self::ErrorKind) -> Self { + Self::from_kind(kind) + } + + fn with_chain(error: E, kind: K) + -> Self + where E: ::std::error::Error + Send + 'static, + K: Into + { + Self::with_chain(error, kind) + } + + fn kind(&self) -> &Self::ErrorKind { + self.kind() + } + + fn iter(&self) -> $crate::Iter { + $crate::Iter::new(Some(self)) + } + + fn chain_err(self, error: F) -> Self + where F: FnOnce() -> EK, + EK: Into<$error_kind_name> { + self.chain_err(error) + } + + fn backtrace(&self) -> Option<&$crate::Backtrace> { + self.backtrace() + } + + impl_extract_backtrace!($error_name + $error_kind_name + $([$link_error_path, $(#[$meta_links])*])*); + } + + #[allow(dead_code)] + impl $error_name { + /// Constructs an error from a kind, and generates a backtrace. + pub fn from_kind(kind: $error_kind_name) -> $error_name { + $error_name( + kind, + $crate::State::default(), + ) + } + + /// Constructs a chained error from another error and a kind, and generates a backtrace. + pub fn with_chain(error: E, kind: K) + -> $error_name + where E: ::std::error::Error + Send + 'static, + K: Into<$error_kind_name> + { + $error_name::with_boxed_chain(Box::new(error), kind) + } + + /// Construct a chained error from another boxed error and a kind, and generates a backtrace + pub fn with_boxed_chain(error: Box<::std::error::Error + Send>, kind: K) + -> $error_name + where K: Into<$error_kind_name> + { + $error_name( + kind.into(), + $crate::State::new::<$error_name>(error, ), + ) + } + + /// Returns the kind of the error. + pub fn kind(&self) -> &$error_kind_name { + &self.0 + } + + /// Iterates over the error chain. + pub fn iter(&self) -> $crate::Iter { + $crate::ChainedError::iter(self) + } + + /// Returns the backtrace associated with this error. + pub fn backtrace(&self) -> Option<&$crate::Backtrace> { + self.1.backtrace() + } + + /// Extends the error chain with a new entry. + pub fn chain_err(self, error: F) -> $error_name + where F: FnOnce() -> EK, EK: Into<$error_kind_name> { + $error_name::with_chain(self, Self::from_kind(error().into())) + } + } + + impl ::std::error::Error for $error_name { + fn description(&self) -> &str { + self.0.description() + } + + #[allow(unknown_lints, unused_doc_comment)] + fn cause(&self) -> Option<&::std::error::Error> { + match self.1.next_error { + Some(ref c) => Some(&**c), + None => { + match self.0 { + $( + $(#[$meta_foreign_links])* + $error_kind_name::$foreign_link_variant(ref foreign_err) => { + foreign_err.cause() + } + ) * + _ => None + } + } + } + } + } + + impl ::std::fmt::Display for $error_name { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::std::fmt::Display::fmt(&self.0, f) + } + } + + $( + $(#[$meta_links])* + impl From<$link_error_path> for $error_name { + fn from(e: $link_error_path) -> Self { + $error_name( + $error_kind_name::$link_variant(e.0), + e.1, + ) + } + } + ) * + + $( + $(#[$meta_foreign_links])* + impl From<$foreign_link_error_path> for $error_name { + fn from(e: $foreign_link_error_path) -> Self { + $error_name::from_kind( + $error_kind_name::$foreign_link_variant(e) + ) + } + } + ) * + + impl From<$error_kind_name> for $error_name { + fn from(e: $error_kind_name) -> Self { + $error_name::from_kind(e) + } + } + + impl<'a> From<&'a str> for $error_name { + fn from(s: &'a str) -> Self { + $error_name::from_kind(s.into()) + } + } + + impl From for $error_name { + fn from(s: String) -> Self { + $error_name::from_kind(s.into()) + } + } + + impl ::std::ops::Deref for $error_name { + type Target = $error_kind_name; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + + // The ErrorKind type + // -------------- + + impl_error_chain_kind! { + /// The kind of an error. + #[derive(Debug)] + pub enum $error_kind_name { + + /// A convenient variant for String. + Msg(s: String) { + description(&s) + display("{}", s) + } + + $( + $(#[$meta_links])* + $link_variant(e: $link_kind_path) { + description(e.description()) + display("{}", e) + } + ) * + + $( + $(#[$meta_foreign_links])* + $foreign_link_variant(err: $foreign_link_error_path) { + description(::std::error::Error::description(err)) + display("{}", err) + } + ) * + + $($error_chunks)* + } + } + + $( + $(#[$meta_links])* + impl From<$link_kind_path> for $error_kind_name { + fn from(e: $link_kind_path) -> Self { + $error_kind_name::$link_variant(e) + } + } + ) * + + impl<'a> From<&'a str> for $error_kind_name { + fn from(s: &'a str) -> Self { + $error_kind_name::Msg(s.to_string()) + } + } + + impl From for $error_kind_name { + fn from(s: String) -> Self { + $error_kind_name::Msg(s) + } + } + + impl From<$error_name> for $error_kind_name { + fn from(e: $error_name) -> Self { + e.0 + } + } + + // The ResultExt trait defines the `chain_err` method. + + /// Additional methods for `Result`, for easy interaction with this crate. + pub trait $result_ext_name { + /// If the `Result` is an `Err` then `chain_err` evaluates the closure, + /// which returns *some type that can be converted to `ErrorKind`*, boxes + /// the original error to store as the cause, then returns a new error + /// containing the original error. + fn chain_err(self, callback: F) -> ::std::result::Result + where F: FnOnce() -> EK, + EK: Into<$error_kind_name>; + } + + impl $result_ext_name for ::std::result::Result where E: ::std::error::Error + Send + 'static { + fn chain_err(self, callback: F) -> ::std::result::Result + where F: FnOnce() -> EK, + EK: Into<$error_kind_name> { + self.map_err(move |e| { + let state = $crate::State::new::<$error_name>(Box::new(e), ); + $crate::ChainedError::new(callback().into(), state) + }) + } + } + + impl $result_ext_name for ::std::option::Option { + fn chain_err(self, callback: F) -> ::std::result::Result + where F: FnOnce() -> EK, + EK: Into<$error_kind_name> { + self.ok_or_else(move || { + $crate::ChainedError::from_kind(callback().into()) + }) + } + } + + + }; +} + +/// Internal macro used for reordering of the fields. +#[doc(hidden)] +#[macro_export] +macro_rules! error_chain_processing { + ( + ({}, $b:tt, $c:tt, $d:tt) + types $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($content, $b, $c, $d) + $($tail)* + } + }; + ( + ($a:tt, {}, $c:tt, $d:tt) + links $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($a, $content, $c, $d) + $($tail)* + } + }; + ( + ($a:tt, $b:tt, {}, $d:tt) + foreign_links $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($a, $b, $content, $d) + $($tail)* + } + }; + ( + ($a:tt, $b:tt, $c:tt, {}) + errors $content:tt + $( $tail:tt )* + ) => { + error_chain_processing! { + ($a, $b, $c, $content) + $($tail)* + } + }; + ( ($a:tt, $b:tt, $c:tt, $d:tt) ) => { + impl_error_chain_processed! { + types $a + links $b + foreign_links $c + errors $d + } + }; +} + +/// Macro for generating error types and traits. See crate level documentation for details. +#[macro_export] +macro_rules! error_chain { + ( $( $block_name:ident { $( $block_content:tt )* } )* ) => { + error_chain_processing! { + ({}, {}, {}, {}) + $($block_name { $( $block_content )* })* + } + }; +} + +/// Macro used to manage the `backtrace` feature. +/// +/// See +/// https://www.reddit.com/r/rust/comments/57virt/hey_rustaceans_got_an_easy_question_ask_here/da5r4ti/?context=3 +/// for more details. +#[macro_export] +#[doc(hidden)] +#[cfg(feature = "backtrace")] +macro_rules! impl_extract_backtrace { + ($error_name: ident + $error_kind_name: ident + $([$link_error_path: path, $(#[$meta_links: meta])*])*) => { + #[allow(unknown_lints, unused_doc_comment)] + fn extract_backtrace(e: &(::std::error::Error + Send + 'static)) + -> Option<::std::sync::Arc<$crate::Backtrace>> { + if let Some(e) = e.downcast_ref::<$error_name>() { + return e.1.backtrace.clone(); + } + $( + $( #[$meta_links] )* + { + if let Some(e) = e.downcast_ref::<$link_error_path>() { + return e.1.backtrace.clone(); + } + } + ) * + None + } + } +} + +/// Macro used to manage the `backtrace` feature. +/// +/// See +/// https://www.reddit.com/r/rust/comments/57virt/hey_rustaceans_got_an_easy_question_ask_here/da5r4ti/?context=3 +/// for more details. +#[macro_export] +#[doc(hidden)] +#[cfg(not(feature = "backtrace"))] +macro_rules! impl_extract_backtrace { + ($error_name: ident + $error_kind_name: ident + $([$link_error_path: path, $(#[$meta_links: meta])*])*) => {} +} diff --git a/error-chain-0.11.0/src/example_generated.rs b/error-chain-0.11.0/src/example_generated.rs new file mode 100644 index 000000000..413407cae --- /dev/null +++ b/error-chain-0.11.0/src/example_generated.rs @@ -0,0 +1,38 @@ +//! These modules show an example of code generated by the macro. **IT MUST NOT BE +//! USED OUTSIDE THIS CRATE**. +//! +//! This is the basic error structure. You can see that `ErrorKind` +//! has been populated in a variety of ways. All `ErrorKind`s get a +//! `Msg` variant for basic errors. When strings are converted to +//! `ErrorKind`s they become `ErrorKind::Msg`. The "links" defined in +//! the macro are expanded to the `Inner` variant, and the +//! "foreign links" to the `Io` variant. +//! +//! Both types come with a variety of `From` conversions as well: +//! `Error` can be created from `ErrorKind`, `&str` and `String`, +//! and the `links` and `foreign_links` error types. `ErrorKind` +//! can be created from the corresponding `ErrorKind`s of the link +//! types, as well as from `&str` and `String`. +//! +//! `into()` and `From::from` are used heavily to massage types into +//! the right shape. Which one to use in any specific case depends on +//! the influence of type inference, but there are some patterns that +//! arise frequently. + +/// Another code generated by the macro. +pub mod inner { + error_chain!{} +} + +error_chain! { + links { + Inner(inner::Error, inner::ErrorKind) #[doc = "Link to another `ErrorChain`."]; + } + foreign_links { + Io(::std::io::Error) #[doc = "Link to a `std::error::Error` type."]; + } + errors { + #[doc = "A custom error kind."] + Custom + } +} diff --git a/error-chain-0.11.0/src/impl_error_chain_kind.rs b/error-chain-0.11.0/src/impl_error_chain_kind.rs new file mode 100644 index 000000000..d6c05c8a8 --- /dev/null +++ b/error-chain-0.11.0/src/impl_error_chain_kind.rs @@ -0,0 +1,541 @@ +// From https://github.com/tailhook/quick-error +// Changes: +// - replace `impl Error` by `impl Item::description` +// - $imeta + +#[macro_export] +#[doc(hidden)] +macro_rules! impl_error_chain_kind { + ( $(#[$meta:meta])* + pub enum $name:ident { $($chunks:tt)* } + ) => { + impl_error_chain_kind!(SORT [pub enum $name $(#[$meta])* ] + items [] buf [] + queue [ $($chunks)* ]); + }; + ( $(#[$meta:meta])* + enum $name:ident { $($chunks:tt)* } + ) => { + impl_error_chain_kind!(SORT [enum $name $(#[$meta])* ] + items [] buf [] + queue [ $($chunks)* ]); + }; + // Queue is empty, can do the work + (SORT [enum $name:ident $( #[$meta:meta] )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [ ] + queue [ ] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [enum $name $( #[$meta] )*] + body [] + queue [$($( #[$imeta] )* + => $iitem: $imode [$( $ivar: $ityp ),*] )*] + ); + impl_error_chain_kind!(IMPLEMENTATIONS $name {$( + $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*} + )*}); + $( + impl_error_chain_kind!(ERROR_CHECK $imode $($ifuncs)*); + )* + }; + (SORT [pub enum $name:ident $( #[$meta:meta] )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [ ] + queue [ ] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [pub enum $name $( #[$meta] )*] + body [] + queue [$($( #[$imeta] )* + => $iitem: $imode [$( $ivar: $ityp ),*] )*] + ); + impl_error_chain_kind!(IMPLEMENTATIONS $name {$( + $iitem: $imode [$(#[$imeta])*] [$( $ivar: $ityp ),*] {$( $ifuncs )*} + )*}); + $( + impl_error_chain_kind!(ERROR_CHECK $imode $($ifuncs)*); + )* + }; + // Add meta to buffer + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )*] + queue [ #[$qmeta:meta] $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* #[$qmeta] ] + queue [$( $tail )*]); + }; + // Add ident to buffer + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )*] + queue [ $qitem:ident $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* + => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$(#[$bmeta])* => $qitem : UNIT [ ] ] + queue [$( $tail )*]); + }; + // Flush buffer on meta after ident + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ #[$qmeta:meta] $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + enum [$( $(#[$emeta])* => $eitem $(( $($etyp),* ))* )* + $(#[$bmeta])* => $bitem: $bmode $(( $($btyp),* ))*] + items [$($( #[$imeta:meta] )* + => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $bitem: $bmode [$( $bvar:$btyp ),*] {} ] + buf [ #[$qmeta] ] + queue [$( $tail )*]); + }; + // Add tuple enum-variant + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] + queue [($( $qvar:ident: $qtyp:ty ),+) $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* => $bitem: TUPLE [$( $qvar:$qtyp ),*] ] + queue [$( $tail )*] + ); + }; + // Add struct enum-variant - e.g. { descr: &'static str } + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] + queue [{ $( $qvar:ident: $qtyp:ty ),+} $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),*] ] + queue [$( $tail )*]); + }; + // Add struct enum-variant, with excess comma - e.g. { descr: &'static str, } + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* => $bitem:ident: UNIT [ ] ] + queue [{$( $qvar:ident: $qtyp:ty ),+ ,} $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )*] + buf [$( #[$bmeta] )* => $bitem: STRUCT [$( $qvar:$qtyp ),*] ] + queue [$( $tail )*]); + }; + // Add braces and flush always on braces + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ {$( $qfuncs:tt )*} $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {$( $qfuncs )*} ] + buf [ ] + queue [$( $tail )*]); + }; + // Flush buffer on double ident + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ $qitem:ident $( $tail:tt )*] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ] + buf [ => $qitem : UNIT [ ] ] + queue [$( $tail )*]); + }; + // Flush buffer on end + (SORT [$( $def:tt )*] + items [$($( #[$imeta:meta] )* + => $iitem:ident: $imode:tt [$( $ivar:ident: $ityp:ty ),*] + {$( $ifuncs:tt )*} )* ] + buf [$( #[$bmeta:meta] )* + => $bitem:ident: $bmode:tt [$( $bvar:ident: $btyp:ty ),*] ] + queue [ ] + ) => { + impl_error_chain_kind!(SORT [$( $def )*] + items [$( $(#[$imeta])* => $iitem: $imode [$( $ivar:$ityp ),*] {$( $ifuncs )*} )* + $(#[$bmeta])* => $bitem: $bmode [$( $bvar:$btyp ),*] {} ] + buf [ ] + queue [ ]); + }; + // Public enum (Queue Empty) + (ENUM_DEFINITION [pub enum $name:ident $( #[$meta:meta] )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [ ] + ) => { + $(#[$meta])* + pub enum $name { + $( + $(#[$imeta])* + $iitem $(($( $ttyp ),*))* $({$( $svar: $styp ),*})*, + )* + + #[doc(hidden)] + __Nonexhaustive {} + } + }; + // Private enum (Queue Empty) + (ENUM_DEFINITION [enum $name:ident $( #[$meta:meta] )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [ ] + ) => { + $(#[$meta])* + enum $name { + $( + $(#[$imeta])* + $iitem $(($( $ttyp ),*))* $({$( $svar: $styp ),*})*, + )* + } + }; + // Unit variant + (ENUM_DEFINITION [$( $def:tt )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [$( #[$qmeta:meta] )* + => $qitem:ident: UNIT [ ] $( $queue:tt )*] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ] + body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* + $( #[$qmeta] )* => $qitem () {} ] + queue [ $($queue)* ] + ); + }; + // Tuple variant + (ENUM_DEFINITION [$( $def:tt )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [$( #[$qmeta:meta] )* + => $qitem:ident: TUPLE [$( $qvar:ident: $qtyp:ty ),+] $( $queue:tt )*] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ] + body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* + $( #[$qmeta] )* => $qitem (($( $qtyp ),*)) {} ] + queue [ $($queue)* ] + ); + }; + // Struct variant + (ENUM_DEFINITION [$( $def:tt )*] + body [$($( #[$imeta:meta] )* + => $iitem:ident ($(($( $ttyp:ty ),+))*) {$({$( $svar:ident: $styp:ty ),*})*} )* ] + queue [$( #[$qmeta:meta] )* + => $qitem:ident: STRUCT [$( $qvar:ident: $qtyp:ty ),*] $( $queue:tt )*] + ) => { + impl_error_chain_kind!(ENUM_DEFINITION [ $($def)* ] + body [$($( #[$imeta] )* => $iitem ($(($( $ttyp ),+))*) {$({$( $svar: $styp ),*})*} )* + $( #[$qmeta] )* => $qitem () {{$( $qvar: $qtyp ),*}} ] + queue [ $($queue)* ] + ); + }; + (IMPLEMENTATIONS + $name:ident {$( + $item:ident: $imode:tt [$(#[$imeta:meta])*] [$( $var:ident: $typ:ty ),*] {$( $funcs:tt )*} + )*} + ) => { + #[allow(unknown_lints, unused, unused_doc_comment)] + impl ::std::fmt::Display for $name { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) + -> ::std::fmt::Result + { + match *self { + $( + $(#[$imeta])* + impl_error_chain_kind!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { + let display_fn = impl_error_chain_kind!(FIND_DISPLAY_IMPL + $name $item: $imode + {$( $funcs )*}); + + display_fn(self, fmt) + } + )* + + _ => Ok(()) + } + } + } + /*#[allow(unused)] + impl ::std::error::Error for $name { + fn description(&self) -> &str { + match *self { + $( + impl_error_chain_kind!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { + impl_error_chain_kind!(FIND_DESCRIPTION_IMPL + $item: $imode self fmt [$( $var ),*] + {$( $funcs )*}) + } + )* + } + } + fn cause(&self) -> Option<&::std::error::Error> { + match *self { + $( + impl_error_chain_kind!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { + impl_error_chain_kind!(FIND_CAUSE_IMPL + $item: $imode [$( $var ),*] + {$( $funcs )*}) + } + )* + } + } + }*/ + #[allow(unknown_lints, unused, unused_doc_comment)] + impl $name { + /// A string describing the error kind. + pub fn description(&self) -> &str { + match *self { + $( + $(#[$imeta])* + impl_error_chain_kind!(ITEM_PATTERN + $name $item: $imode [$( ref $var ),*] + ) => { + impl_error_chain_kind!(FIND_DESCRIPTION_IMPL + $item: $imode self fmt [$( $var ),*] + {$( $funcs )*}) + } + )* + + _ => "", + } + } + } + $( + impl_error_chain_kind!(FIND_FROM_IMPL + $name $item: $imode [$( $var:$typ ),*] + {$( $funcs )*}); + )* + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*} + ) => { + |impl_error_chain_kind!(IDENT $self_): &$name, f: &mut ::std::fmt::Formatter| { + write!(f, $( $exprs )*) + } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { display($pattern:expr) $( $tail:tt )*} + ) => { + |_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern) } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { display($pattern:expr, $( $exprs:tt )*) $( $tail:tt )*} + ) => { + |_, f: &mut ::std::fmt::Formatter| { write!(f, $pattern, $( $exprs )*) } + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { $t:tt $( $tail:tt )*} + ) => { + impl_error_chain_kind!(FIND_DISPLAY_IMPL + $name $item: $imode + {$( $tail )*}) + }; + (FIND_DISPLAY_IMPL $name:ident $item:ident: $imode:tt + { } + ) => { + |self_: &$name, f: &mut ::std::fmt::Formatter| { + write!(f, "{}", self_.description()) + } + }; + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { description($expr:expr) $( $tail:tt )*} + ) => { + $expr + }; + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { $t:tt $( $tail:tt )*} + ) => { + impl_error_chain_kind!(FIND_DESCRIPTION_IMPL + $item: $imode $me $fmt [$( $var ),*] + {$( $tail )*}) + }; + (FIND_DESCRIPTION_IMPL $item:ident: $imode:tt $me:ident $fmt:ident + [$( $var:ident ),*] + { } + ) => { + stringify!($item) + }; + (FIND_CAUSE_IMPL $item:ident: $imode:tt + [$( $var:ident ),*] + { cause($expr:expr) $( $tail:tt )*} + ) => { + Some($expr) + }; + (FIND_CAUSE_IMPL $item:ident: $imode:tt + [$( $var:ident ),*] + { $t:tt $( $tail:tt )*} + ) => { + impl_error_chain_kind!(FIND_CAUSE_IMPL + $item: $imode [$( $var ),*] + { $($tail)* }) + }; + (FIND_CAUSE_IMPL $item:ident: $imode:tt + [$( $var:ident ),*] + { } + ) => { + None + }; + (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt + [$( $var:ident: $typ:ty ),*] + { from() $( $tail:tt )*} + ) => { + $( + impl From<$typ> for $name { + fn from($var: $typ) -> $name { + $name::$item($var) + } + } + )* + impl_error_chain_kind!(FIND_FROM_IMPL + $name $item: $imode [$( $var:$typ ),*] + {$( $tail )*}); + }; + (FIND_FROM_IMPL $name:ident $item:ident: UNIT + [ ] + { from($ftyp:ty) $( $tail:tt )*} + ) => { + impl From<$ftyp> for $name { + fn from(_discarded_error: $ftyp) -> $name { + $name::$item + } + } + impl_error_chain_kind!(FIND_FROM_IMPL + $name $item: UNIT [ ] + {$( $tail )*}); + }; + (FIND_FROM_IMPL $name:ident $item:ident: TUPLE + [$( $var:ident: $typ:ty ),*] + { from($fvar:ident: $ftyp:ty) -> ($( $texpr:expr ),*) $( $tail:tt )*} + ) => { + impl From<$ftyp> for $name { + fn from($fvar: $ftyp) -> $name { + $name::$item($( $texpr ),*) + } + } + impl_error_chain_kind!(FIND_FROM_IMPL + $name $item: TUPLE [$( $var:$typ ),*] + { $($tail)* }); + }; + (FIND_FROM_IMPL $name:ident $item:ident: STRUCT + [$( $var:ident: $typ:ty ),*] + { from($fvar:ident: $ftyp:ty) -> {$( $tvar:ident: $texpr:expr ),*} $( $tail:tt )*} + ) => { + impl From<$ftyp> for $name { + fn from($fvar: $ftyp) -> $name { + $name::$item { + $( $tvar: $texpr ),* + } + } + } + impl_error_chain_kind!(FIND_FROM_IMPL + $name $item: STRUCT [$( $var:$typ ),*] + { $($tail)* }); + }; + (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt + [$( $var:ident: $typ:ty ),*] + { $t:tt $( $tail:tt )*} + ) => { + impl_error_chain_kind!(FIND_FROM_IMPL + $name $item: $imode [$( $var:$typ ),*] + {$( $tail )*} + ); + }; + (FIND_FROM_IMPL $name:ident $item:ident: $imode:tt + [$( $var:ident: $typ:ty ),*] + { } + ) => { + }; + (ITEM_BODY $(#[$imeta:meta])* $item:ident: UNIT + ) => { }; + (ITEM_BODY $(#[$imeta:meta])* $item:ident: TUPLE + [$( $typ:ty ),*] + ) => { + ($( $typ ),*) + }; + (ITEM_BODY $(#[$imeta:meta])* $item:ident: STRUCT + [$( $var:ident: $typ:ty ),*] + ) => { + {$( $var:$typ ),*} + }; + (ITEM_PATTERN $name:ident $item:ident: UNIT [] + ) => { + $name::$item + }; + (ITEM_PATTERN $name:ident $item:ident: TUPLE + [$( ref $var:ident ),*] + ) => { + $name::$item ($( ref $var ),*) + }; + (ITEM_PATTERN $name:ident $item:ident: STRUCT + [$( ref $var:ident ),*] + ) => { + $name::$item {$( ref $var ),*} + }; + // This one should match all allowed sequences in "funcs" but not match + // anything else. + // This is to contrast FIND_* clauses which just find stuff they need and + // skip everything else completely + (ERROR_CHECK $imode:tt display($self_:tt) -> ($( $exprs:tt )*) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt display($pattern: expr) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt display($pattern: expr, $( $exprs:tt )*) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt description($expr:expr) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt cause($expr:expr) $($tail:tt)*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt from() $($tail:tt)*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK $imode:tt from($ftyp:ty) $($tail:tt)*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA $imode $($tail)*); }; + (ERROR_CHECK TUPLE from($fvar:ident: $ftyp:ty) -> ($( $e:expr ),*) $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA TUPLE $($tail)*); }; + (ERROR_CHECK STRUCT from($fvar:ident: $ftyp:ty) -> {$( $v:ident: $e:expr ),*} $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK_COMMA STRUCT $($tail)*); }; + (ERROR_CHECK $imode:tt ) => {}; + (ERROR_CHECK_COMMA $imode:tt , $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK $imode $($tail)*); }; + (ERROR_CHECK_COMMA $imode:tt $( $tail:tt )*) + => { impl_error_chain_kind!(ERROR_CHECK $imode $($tail)*); }; + // Utility functions + (IDENT $ident:ident) => { $ident } +} diff --git a/error-chain-0.11.0/src/lib.rs b/error-chain-0.11.0/src/lib.rs new file mode 100644 index 000000000..d0881fcef --- /dev/null +++ b/error-chain-0.11.0/src/lib.rs @@ -0,0 +1,865 @@ +#![deny(missing_docs)] +#![allow(unknown_lints)] // to be removed when unused_doc_comments lints is merged +#![doc(html_root_url = "https://docs.rs/error-chain/0.11.0")] + +//! A library for consistent and reliable error handling +//! +//! error-chain makes it easy to take full advantage of Rust's +//! powerful error handling features without the overhead of +//! maintaining boilerplate error types and conversions. It implements +//! an opinionated strategy for defining your own error types, as well +//! as conversions from others' error types. +//! +//! ## Quick start +//! +//! If you just want to set up your new project with error-chain, +//! follow the [quickstart.rs] template, and read this [intro] +//! to error-chain. +//! +//! [quickstart.rs]: https://github.com/rust-lang-nursery/error-chain/blob/master/examples/quickstart.rs +//! [intro]: http://brson.github.io/2016/11/30/starting-with-error-chain +//! +//! ## Why error chain? +//! +//! * error-chain is easy to configure. Handle errors robustly with minimal +//! effort. +//! * Basic error handling requires no maintenance of custom error types +//! nor the [`From`] conversions that make `?` work. +//! * error-chain scales from simple error handling strategies to more +//! rigorous. Return formatted strings for simple errors, only +//! introducing error variants and their strong typing as needed for +//! advanced error recovery. +//! * error-chain makes it trivial to correctly manage the [cause] of +//! the errors generated by your own code. This is the "chaining" +//! in "error-chain". +//! +//! [cause]: https://doc.rust-lang.org/std/error/trait.Error.html#method.cause +//! +//! ## Principles of error-chain +//! +//! error-chain is based on the following principles: +//! +//! * No error should ever be discarded. This library primarily +//! makes it easy to "chain" errors with the [`chain_err`] method. +//! * Introducing new errors is trivial. Simple errors can be introduced +//! at the error site with just a string. +//! * Handling errors is possible with pattern matching. +//! * Conversions between error types are done in an automatic and +//! consistent way - [`From`] conversion behavior is never specified +//! explicitly. +//! * Errors implement [`Send`]. +//! * Errors can carry backtraces. +//! +//! Similar to other libraries like [error-type] and [quick-error], +//! this library introduces the error chaining mechanism originally +//! employed by Cargo. The [`error_chain!`] macro declares the types +//! and implementation boilerplate necessary for fulfilling a +//! particular error-handling strategy. Most importantly it defines a +//! custom error type (called [`Error`] by convention) and the [`From`] +//! conversions that let the `?` operator work. +//! +//! This library differs in a few ways from previous error libs: +//! +//! * Instead of defining the custom [`Error`] type as an enum, it is a +//! struct containing an [`ErrorKind`][] (which defines the +//! [`description`] and [`display_chain`] methods for the error), an opaque, +//! optional, boxed [`std::error::Error`]` + `[`Send`]` + 'static` object +//! (which defines the [`cause`], and establishes the links in the +//! error chain), and a [`Backtrace`]. +//! * The macro also defines a [`ResultExt`] trait that defines a +//! [`chain_err`] method. This method on all [`std::error::Error`]` + `[`Send`]` + 'static` +//! types extends the error chain by boxing the current +//! error into an opaque object and putting it inside a new concrete +//! error. +//! * It provides automatic [`From`] conversions between other error types +//! defined by the [`error_chain!`] that preserve type information, +//! and facilitate seamless error composition and matching of composed +//! errors. +//! * It provides automatic [`From`] conversions between any other error +//! type that hides the type of the other error in the [`cause`] box. +//! * If `RUST_BACKTRACE` is enabled, it collects a single backtrace at +//! the earliest opportunity and propagates it down the stack through +//! [`From`] and [`ResultExt`] conversions. +//! +//! To accomplish its goals it makes some tradeoffs: +//! +//! * The split between the [`Error`] and [`ErrorKind`] types can make it +//! slightly more cumbersome to instantiate new (unchained) errors, +//! requiring an [`Into`] or [`From`] conversion; as well as slightly +//! more cumbersome to match on errors with another layer of types +//! to match. +//! * Because the error type contains [`std::error::Error`]` + `[`Send`]` + 'static` objects, +//! it can't implement [`PartialEq`] for easy comparisons. +//! +//! ## Declaring error types +//! +//! Generally, you define one family of error types per crate, though +//! it's also perfectly fine to define error types on a finer-grained +//! basis, such as per module. +//! +//! Assuming you are using crate-level error types, typically you will +//! define an `errors` module and inside it call [`error_chain!`]: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! mod other_error { +//! error_chain! {} +//! } +//! +//! error_chain! { +//! // The type defined for this error. These are the conventional +//! // and recommended names, but they can be arbitrarily chosen. +//! // +//! // It is also possible to leave this section out entirely, or +//! // leave it empty, and these names will be used automatically. +//! types { +//! Error, ErrorKind, ResultExt, Result; +//! } +//! +//! // Without the `Result` wrapper: +//! // +//! // types { +//! // Error, ErrorKind, ResultExt; +//! // } +//! +//! // Automatic conversions between this error chain and other +//! // error chains. In this case, it will e.g. generate an +//! // `ErrorKind` variant called `Another` which in turn contains +//! // the `other_error::ErrorKind`, with conversions from +//! // `other_error::Error`. +//! // +//! // Optionally, some attributes can be added to a variant. +//! // +//! // This section can be empty. +//! links { +//! Another(other_error::Error, other_error::ErrorKind) #[cfg(unix)]; +//! } +//! +//! // Automatic conversions between this error chain and other +//! // error types not defined by the `error_chain!`. These will be +//! // wrapped in a new error with, in the first case, the +//! // `ErrorKind::Fmt` variant. The description and cause will +//! // forward to the description and cause of the original error. +//! // +//! // Optionally, some attributes can be added to a variant. +//! // +//! // This section can be empty. +//! foreign_links { +//! Fmt(::std::fmt::Error); +//! Io(::std::io::Error) #[cfg(unix)]; +//! } +//! +//! // Define additional `ErrorKind` variants. Define custom responses with the +//! // `description` and `display` calls. +//! errors { +//! InvalidToolchainName(t: String) { +//! description("invalid toolchain name") +//! display("invalid toolchain name: '{}'", t) +//! } +//! +//! // You can also add commas after description/display. +//! // This may work better with some editor auto-indentation modes: +//! UnknownToolchainVersion(v: String) { +//! description("unknown toolchain version"), // note the , +//! display("unknown toolchain version: '{}'", v), // trailing comma is allowed +//! } +//! } +//! } +//! +//! # fn main() {} +//! ``` +//! +//! Each section, `types`, `links`, `foreign_links`, and `errors` may +//! be omitted if it is empty. +//! +//! This populates the module with a number of definitions, +//! the most important of which are the [`Error`] type +//! and the [`ErrorKind`] type. An example of generated code can be found in the +//! [example_generated](example_generated/index.html) module. +//! +//! ## Returning new errors +//! +//! Introducing new error chains, with a string message: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! {} +//! fn foo() -> Result<()> { +//! Err("foo error!".into()) +//! } +//! ``` +//! +//! Introducing new error chains, with an [`ErrorKind`]: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! error_chain! { +//! errors { FooError } +//! } +//! +//! fn foo() -> Result<()> { +//! Err(ErrorKind::FooError.into()) +//! } +//! ``` +//! +//! Note that the return type is the typedef [`Result`], which is +//! defined by the macro as `pub type Result = +//! ::std::result::Result`. Note that in both cases +//! [`.into()`] is called to convert a type into the [`Error`] type; both +//! strings and [`ErrorKind`] have [`From`] conversions to turn them into +//! [`Error`]. +//! +//! When the error is emitted behind the `?` operator, the explicit conversion +//! isn't needed; `Err(ErrorKind)` will automatically be converted to `Err(Error)`. +//! So the below is equivalent to the previous: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! { errors { FooError } } +//! fn foo() -> Result<()> { +//! Ok(Err(ErrorKind::FooError)?) +//! } +//! +//! fn bar() -> Result<()> { +//! Ok(Err("bogus!")?) +//! } +//! ``` +//! +//! ## The `bail!` macro +//! +//! The above method of introducing new errors works but is a little +//! verbose. Instead, we can use the [`bail!`] macro, which performs an early return +//! with conversions done automatically. +//! +//! With [`bail!`] the previous examples look like: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! { errors { FooError } } +//! fn foo() -> Result<()> { +//! if true { +//! bail!(ErrorKind::FooError); +//! } else { +//! Ok(()) +//! } +//! } +//! +//! fn bar() -> Result<()> { +//! if true { +//! bail!("bogus!"); +//! } else { +//! Ok(()) +//! } +//! } +//! ``` +//! +//! ## Chaining errors +//! error-chain supports extending an error chain by appending new errors. +//! This can be done on a Result or on an existing Error. +//! +//! To extend the error chain: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! {} +//! # fn do_something() -> Result<()> { unimplemented!() } +//! # fn test() -> Result<()> { +//! let res: Result<()> = do_something().chain_err(|| "something went wrong"); +//! # Ok(()) +//! # } +//! ``` +//! +//! [`chain_err`] can be called on any [`Result`] type where the contained +//! error type implements [`std::error::Error`]` + `[`Send`]` + 'static`, as long as +//! the [`Result`] type's corresponding [`ResultExt`] trait is in scope. If +//! the [`Result`] is an `Err` then [`chain_err`] evaluates the closure, +//! which returns *some type that can be converted to [`ErrorKind`]*, +//! boxes the original error to store as the cause, then returns a new +//! error containing the original error. +//! +//! Calling [`chain_err`][Error_chain_err] on an existing [`Error`] instance has +//! the same signature and produces the same outcome as being called on a +//! [`Result`] matching the properties described above. This is most useful when +//! partially handling errors using the [`map_err`] function. +//! +//! To chain an error directly, use [`with_chain`]: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # error_chain! {} +//! # fn do_something() -> Result<()> { unimplemented!() } +//! # fn test() -> Result<()> { +//! let res: Result<()> = +//! do_something().map_err(|e| Error::with_chain(e, "something went wrong")); +//! # Ok(()) +//! # } +//! ``` +//! +//! ## Linking errors +//! +//! To convert an error from another error chain to this error chain: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() {} +//! # mod other { error_chain! {} } +//! error_chain! { +//! links { +//! OtherError(other::Error, other::ErrorKind); +//! } +//! } +//! +//! fn do_other_thing() -> other::Result<()> { unimplemented!() } +//! +//! # fn test() -> Result<()> { +//! let res: Result<()> = do_other_thing().map_err(|e| e.into()); +//! # Ok(()) +//! # } +//! ``` +//! +//! The [`Error`] and [`ErrorKind`] types implements [`From`] for the corresponding +//! types of all linked error chains. Linked errors do not introduce a new +//! cause to the error chain. +//! +//! ## Matching errors +//! +//! error-chain error variants are matched with simple patterns. +//! [`Error`] is a tuple struct and its first field is the [`ErrorKind`], +//! making dispatching on error kinds relatively compact: +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! # fn main() { +//! error_chain! { +//! errors { +//! InvalidToolchainName(t: String) { +//! description("invalid toolchain name") +//! display("invalid toolchain name: '{}'", t) +//! } +//! } +//! } +//! +//! match Error::from("error!") { +//! Error(ErrorKind::InvalidToolchainName(_), _) => { } +//! Error(ErrorKind::Msg(_), _) => { } +//! _ => { } +//! } +//! # } +//! ``` +//! +//! Chained errors are also matched with (relatively) compact syntax +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! mod utils { +//! error_chain! { +//! errors { +//! BadStuff { +//! description("bad stuff") +//! } +//! } +//! } +//! } +//! +//! mod app { +//! error_chain! { +//! links { +//! Utils(::utils::Error, ::utils::ErrorKind); +//! } +//! } +//! } +//! +//! +//! # fn main() { +//! match app::Error::from("error!") { +//! app::Error(app::ErrorKind::Utils(utils::ErrorKind::BadStuff), _) => { } +//! _ => { } +//! } +//! # } +//! ``` +//! +//! ## Inspecting errors +//! +//! An error-chain error contains information about the error itself, a backtrace, and the chain +//! of causing errors. For reporting purposes, this information can be accessed as follows. +//! +//! ``` +//! # #[macro_use] extern crate error_chain; +//! use error_chain::ChainedError; // for e.display_chain() +//! +//! error_chain! { +//! errors { +//! InvalidToolchainName(t: String) { +//! description("invalid toolchain name") +//! display("invalid toolchain name: '{}'", t) +//! } +//! } +//! } +//! +//! # fn main() { +//! // Generate an example error to inspect: +//! let e = "xyzzy".parse::() +//! .chain_err(|| ErrorKind::InvalidToolchainName("xyzzy".to_string())) +//! .unwrap_err(); +//! +//! // Get the brief description of the error: +//! assert_eq!(e.description(), "invalid toolchain name"); +//! +//! // Get the display version of the error: +//! assert_eq!(e.to_string(), "invalid toolchain name: 'xyzzy'"); +//! +//! // Get the full cause and backtrace: +//! println!("{}", e.display_chain().to_string()); +//! // Error: invalid toolchain name: 'xyzzy' +//! // Caused by: invalid digit found in string +//! // stack backtrace: +//! // 0: 0x7fa9f684fc94 - backtrace::backtrace::libunwind::trace +//! // at src/backtrace/libunwind.rs:53 +//! // - backtrace::backtrace::trace +//! // at src/backtrace/mod.rs:42 +//! // 1: 0x7fa9f6850b0e - backtrace::capture::{{impl}}::new +//! // at out/capture.rs:79 +//! // [..] +//! # } +//! ``` +//! +//! The [`Error`] and [`ErrorKind`] types also allow programmatic access to these elements. +//! +//! ## Foreign links +//! +//! Errors that do not conform to the same conventions as this library +//! can still be included in the error chain. They are considered "foreign +//! errors", and are declared using the `foreign_links` block of the +//! [`error_chain!`] macro. [`Error`]s are automatically created from +//! foreign errors by the `?` operator. +//! +//! Foreign links and regular links have one crucial difference: +//! [`From`] conversions for regular links *do not introduce a new error +//! into the error chain*, while conversions for foreign links *always +//! introduce a new error into the error chain*. So for the example +//! above all errors deriving from the [`std::fmt::Error`] type will be +//! presented to the user as a new [`ErrorKind`] variant, and the +//! cause will be the original [`std::fmt::Error`] error. In contrast, when +//! `other_error::Error` is converted to `Error` the two `ErrorKind`s +//! are converted between each other to create a new `Error` but the +//! old error is discarded; there is no "cause" created from the +//! original error. +//! +//! ## Backtraces +//! +//! If the `RUST_BACKTRACE` environment variable is set to anything +//! but ``0``, the earliest non-foreign error to be generated creates +//! a single backtrace, which is passed through all [`From`] conversions +//! and [`chain_err`] invocations of compatible types. To read the +//! backtrace just call the [`backtrace`] method. +//! +//! Backtrace generation can be disabled by turning off the `backtrace` feature. +//! +//! The Backtrace contains a Vec of [`BacktraceFrame`]s that can be operated +//! on directly. For example, to only see the files and line numbers of code +//! within your own project. +//! +//! ``` +//! # #[macro_use] +//! # extern crate error_chain; +//! # mod errors { +//! # error_chain! { +//! # foreign_links { +//! # Io(::std::io::Error); +//! # } +//! # } +//! # } +//! # use errors::*; +//! # #[cfg(feature="backtrace")] +//! # fn main() { +//! if let Err(ref e) = open_file() { +//! if let Some(backtrace) = e.backtrace() { +//! let frames = backtrace.frames(); +//! for frame in frames.iter() { +//! for symbol in frame.symbols().iter() { +//! if let (Some(file), Some(lineno)) = (symbol.filename(), symbol.lineno()) { +//! if file.display().to_string()[0..3] == "src".to_string(){ +//! println!("{}:{}", file.display().to_string(), lineno); +//! } +//! } +//! } +//! } +//! } +//! }; +//! # } +//! # #[cfg(not(feature="backtrace"))] +//! # fn main() { } +//! +//! fn open_file() -> Result<()> { +//! std::fs::File::open("does_not_exist")?; +//! Ok(()) +//! } +//! ``` +//! +//! ## Iteration +//! +//! The [`iter`] method returns an iterator over the chain of error boxes. +//! +//! [error-type]: https://github.com/DanielKeep/rust-error-type +//! [quick-error]: https://github.com/tailhook/quick-error + +//! [`display_chain`]: trait.ChainedError.html#method.display_chain +//! [`error_chain!`]: macro.error_chain.html +//! [`bail!`]: macro.bail.html +//! [`Backtrace`]: struct.Backtrace.html + +//! [`Error`]: example_generated/struct.Error.html +//! [`with_chain`]: example_generated/struct.Error.html#method.with_chain +//! [Error_chain_err]: example_generated/struct.Error.html#method.chain_err +//! [`cause`]: example_generated/struct.Error.html#method.cause +//! [`backtrace`]: example_generated/struct.Error.html#method.backtrace +//! [`iter`]: example_generated/struct.Error.html#method.iter +//! [`ErrorKind`]: example_generated/enum.ErrorKind.html +//! [`description`]: example_generated/enum.ErrorKind.html#method.description +//! [`Result`]: example_generated/type.Result.html +//! [`ResultExt`]: example_generated/trait.ResultExt.html +//! [`chain_err`]: example_generated/trait.ResultExt.html#tymethod.chain_err + +//! [`std::error::Error`]: https://doc.rust-lang.org/std/error/trait.Error.html +//! [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html +//! [`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html +//! [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html +//! [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html +//! [`std::fmt::Error`]: https://doc.rust-lang.org/std/fmt/struct.Error.html +//! [`.into()`]: https://doc.rust-lang.org/std/convert/trait.Into.html#tymethod.into +//! [`map_err`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err +//! [`BacktraceFrame`]: https://docs.rs/backtrace/0.3.2/backtrace/struct.BacktraceFrame.html + + +#[cfg(feature = "backtrace")] +extern crate backtrace; + +use std::error; +use std::iter::Iterator; +#[cfg(feature = "backtrace")] +use std::sync::Arc; +use std::fmt; + +#[cfg(feature = "backtrace")] +pub use backtrace::Backtrace; +#[cfg(not(feature = "backtrace"))] +/// Dummy type used when the `backtrace` feature is disabled. +pub type Backtrace = (); + +#[macro_use] +mod impl_error_chain_kind; +#[macro_use] +mod error_chain; +#[macro_use] +mod quick_main; +pub use quick_main::ExitCode; +#[cfg(feature = "example_generated")] +pub mod example_generated; + +#[derive(Debug)] +/// Iterator over the error chain using the `Error::cause()` method. +pub struct Iter<'a>(Option<&'a error::Error>); + +impl<'a> Iter<'a> { + /// Returns a new iterator over the error chain using `Error::cause()`. + pub fn new(err: Option<&'a error::Error>) -> Iter<'a> { + Iter(err) + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = &'a error::Error; + + fn next<'b>(&'b mut self) -> Option<&'a error::Error> { + match self.0.take() { + Some(e) => { + self.0 = e.cause(); + Some(e) + } + None => None, + } + } +} + +/// Returns a backtrace of the current call stack if `RUST_BACKTRACE` +/// is set to anything but ``0``, and `None` otherwise. This is used +/// in the generated error implementations. +#[cfg(feature = "backtrace")] +#[doc(hidden)] +pub fn make_backtrace() -> Option> { + use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering}; + + // The lowest bit indicates whether the value was computed, + // while the second lowest bit is the actual "enabled" bit. + static BACKTRACE_ENABLED_CACHE: AtomicUsize = ATOMIC_USIZE_INIT; + + let enabled = match BACKTRACE_ENABLED_CACHE.load(Ordering::Relaxed) { + 0 => { + let enabled = match std::env::var_os("RUST_BACKTRACE") { + Some(ref val) if val != "0" => true, + _ => false + }; + let encoded = ((enabled as usize) << 1) | 1; + BACKTRACE_ENABLED_CACHE.store(encoded, Ordering::Relaxed); + enabled + } + encoded => (encoded >> 1) != 0 + }; + + if enabled { + Some(Arc::new(Backtrace::new())) + } else { + None + } +} + +/// This trait is implemented on all the errors generated by the `error_chain` +/// macro. +pub trait ChainedError: error::Error + Send + 'static { + /// Associated kind type. + type ErrorKind; + + /// Constructs an error from a kind, and generates a backtrace. + fn from_kind(kind: Self::ErrorKind) -> Self where Self: Sized; + + /// Constructs a chained error from another error and a kind, and generates a backtrace. + fn with_chain(error: E, kind: K) -> Self + where Self: Sized, + E: ::std::error::Error + Send + 'static, + K: Into; + + /// Returns the kind of the error. + fn kind(&self) -> &Self::ErrorKind; + + /// Iterates over the error chain. + fn iter(&self) -> Iter; + + /// Returns the backtrace associated with this error. + fn backtrace(&self) -> Option<&Backtrace>; + + /// Returns an object which implements `Display` for printing the full + /// context of this error. + /// + /// The full cause chain and backtrace, if present, will be printed. + fn display_chain<'a>(&'a self) -> DisplayChain<'a, Self> { + DisplayChain(self) + } + + /// Extends the error chain with a new entry. + fn chain_err(self, error: F) -> Self + where F: FnOnce() -> EK, + EK: Into; + + /// Creates an error from its parts. + #[doc(hidden)] + fn new(kind: Self::ErrorKind, state: State) -> Self where Self: Sized; + + /// Returns the first known backtrace, either from its State or from one + /// of the errors from `foreign_links`. + #[cfg(feature = "backtrace")] + #[doc(hidden)] + fn extract_backtrace(e: &(error::Error + Send + 'static)) -> Option> + where Self: Sized; +} + +/// A struct which formats an error for output. +#[derive(Debug)] +pub struct DisplayChain<'a, T: 'a + ?Sized>(&'a T); + +impl<'a, T> fmt::Display for DisplayChain<'a, T> + where T: ChainedError +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + // Keep `try!` for 1.10 support + try!(writeln!(fmt, "Error: {}", self.0)); + + for e in self.0.iter().skip(1) { + try!(writeln!(fmt, "Caused by: {}", e)); + } + + if let Some(backtrace) = self.0.backtrace() { + try!(writeln!(fmt, "{:?}", backtrace)); + } + + Ok(()) + } +} + +/// Common state between errors. +#[derive(Debug)] +#[doc(hidden)] +pub struct State { + /// Next error in the error chain. + pub next_error: Option>, + /// Backtrace for the current error. + #[cfg(feature = "backtrace")] + pub backtrace: Option>, +} + +impl Default for State { + #[cfg(feature = "backtrace")] + fn default() -> State { + State { + next_error: None, + backtrace: make_backtrace(), + } + } + + #[cfg(not(feature = "backtrace"))] + fn default() -> State { + State { next_error: None } + } +} + +impl State { + /// Creates a new State type + #[cfg(feature = "backtrace")] + pub fn new(e: Box) -> State { + let backtrace = CE::extract_backtrace(&*e).or_else(make_backtrace); + State { + next_error: Some(e), + backtrace: backtrace, + } + } + + /// Creates a new State type + #[cfg(not(feature = "backtrace"))] + pub fn new(e: Box) -> State { + State { next_error: Some(e) } + } + + /// Returns the inner backtrace if present. + #[cfg(feature = "backtrace")] + pub fn backtrace(&self) -> Option<&Backtrace> { + self.backtrace.as_ref().map(|v| &**v) + } + + /// Returns the inner backtrace if present. + #[cfg(not(feature = "backtrace"))] + pub fn backtrace(&self) -> Option<&Backtrace> { + None + } +} + +/// Exits a function early with an error +/// +/// The `bail!` macro provides an easy way to exit a function. +/// `bail!(expr)` is equivalent to writing. +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! { } +/// # fn main() { } +/// # fn foo() -> Result<()> { +/// # let expr = ""; +/// return Err(expr.into()); +/// # } +/// ``` +/// +/// And as shorthand it takes a formatting string a la `println!`: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! { } +/// # fn main() { } +/// # fn foo() -> Result<()> { +/// # let n = 0; +/// bail!("bad number: {}", n); +/// # } +/// ``` +/// +/// # Examples +/// +/// Bailing on a custom error: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # fn main() {} +/// error_chain! { +/// errors { FooError } +/// } +/// +/// fn foo() -> Result<()> { +/// if bad_condition() { +/// bail!(ErrorKind::FooError); +/// } +/// +/// Ok(()) +/// } +/// +/// # fn bad_condition() -> bool { true } +/// ``` +/// +/// Bailing on a formatted string: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # fn main() {} +/// error_chain! { } +/// +/// fn foo() -> Result<()> { +/// if let Some(bad_num) = bad_condition() { +/// bail!("so bad: {}", bad_num); +/// } +/// +/// Ok(()) +/// } +/// +/// # fn bad_condition() -> Option { None } +/// ``` +#[macro_export] +macro_rules! bail { + ($e:expr) => { + return Err($e.into()); + }; + ($fmt:expr, $($arg:tt)+) => { + return Err(format!($fmt, $($arg)+).into()); + }; +} + +/// Exits a function early with an error if the condition is not satisfied +/// +/// The `ensure!` macro is a convenience helper that provides a way to exit +/// a function with an error if the given condition fails. +/// +/// As an example, `ensure!(condition, "error code: {}", errcode)` is equivalent to +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! { } +/// # fn main() { } +/// # fn foo() -> Result<()> { +/// # let errcode = 0u8; +/// # let condition = true; +/// if !condition { +/// bail!("error code: {}", errcode); +/// } +/// # Ok(()) +/// # } +/// ``` +/// +/// See documentation for `bail!` macro for further details. +#[macro_export] +macro_rules! ensure { + ($cond:expr, $e:expr) => { + if !($cond) { + bail!($e); + } + }; + ($cond:expr, $fmt:expr, $($arg:tt)+) => { + if !($cond) { + bail!($fmt, $($arg)+); + } + }; +} + +#[doc(hidden)] +pub mod mock { + error_chain!{} +} diff --git a/error-chain-0.11.0/src/quick_main.rs b/error-chain-0.11.0/src/quick_main.rs new file mode 100644 index 000000000..f81e7d704 --- /dev/null +++ b/error-chain-0.11.0/src/quick_main.rs @@ -0,0 +1,77 @@ +/// Convenient wrapper to be able to use `?` and such in the main. You can +/// use it with a separated function: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! {} +/// # fn main() { +/// quick_main!(run); +/// # } +/// +/// fn run() -> Result<()> { +/// Err("error".into()) +/// } +/// ``` +/// +/// or with a closure: +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! {} +/// # fn main() { +/// quick_main!(|| -> Result<()> { +/// Err("error".into()) +/// }); +/// # } +/// ``` +/// +/// You can also set the exit value of the process by returning a type that implements [`ExitCode`](trait.ExitCode.html): +/// +/// ``` +/// # #[macro_use] extern crate error_chain; +/// # error_chain! {} +/// # fn main() { +/// quick_main!(run); +/// # } +/// +/// fn run() -> Result { +/// Err("error".into()) +/// } +/// ``` +#[macro_export] +macro_rules! quick_main { + ($main:expr) => { + fn main() { + use ::std::io::Write; + + ::std::process::exit(match $main() { + Ok(ret) => $crate::ExitCode::code(ret), + Err(ref e) => { + write!(&mut ::std::io::stderr(), "{}", $crate::ChainedError::display_chain(e)) + .expect("Error writing to stderr"); + + 1 + } + }); + } + }; +} + +/// Represents a value that can be used as the exit status of the process. +/// See [`quick_main!`](macro.quick_main.html). +pub trait ExitCode { + /// Returns the value to use as the exit status. + fn code(self) -> i32; +} + +impl ExitCode for i32 { + fn code(self) -> i32 { + self + } +} + +impl ExitCode for () { + fn code(self) -> i32 { + 0 + } +} diff --git a/error-chain-0.11.0/tests/quick_main.rs b/error-chain-0.11.0/tests/quick_main.rs new file mode 100644 index 000000000..4ada3b4e0 --- /dev/null +++ b/error-chain-0.11.0/tests/quick_main.rs @@ -0,0 +1,28 @@ +#![allow(dead_code)] +#[macro_use] +extern crate error_chain; + +error_chain!(); + +mod unit { + use super::*; + quick_main!(run); + + fn run() -> Result<()> { + Ok(()) + } +} + +mod i32 { + use super::*; + quick_main!(run); + + fn run() -> Result { + Ok(1) + } +} + +mod closure { + use super::*; + quick_main!(|| -> Result<()> { Ok(()) }); +} diff --git a/error-chain-0.11.0/tests/tests.rs b/error-chain-0.11.0/tests/tests.rs new file mode 100644 index 000000000..e603e02af --- /dev/null +++ b/error-chain-0.11.0/tests/tests.rs @@ -0,0 +1,628 @@ +#![allow(dead_code)] + +#[macro_use] +extern crate error_chain; + +#[test] +fn smoke_test_1() { + error_chain! { + types { + Error, ErrorKind, ResultExt, Result; + } + + links { } + + foreign_links { } + + errors { } + }; +} + +#[test] +fn smoke_test_2() { + error_chain! { + types { } + + links { } + + foreign_links { } + + errors { } + }; +} + +#[test] +fn smoke_test_3() { + error_chain! { + links { } + + foreign_links { } + + errors { } + }; +} + +#[test] +fn smoke_test_4() { + error_chain! { + links { } + + foreign_links { } + + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code") + display("http request returned an unsuccessful status code: {}", e) + } + } + }; +} + +#[test] +fn smoke_test_5() { + error_chain! { + types { } + + links { } + + foreign_links { } + + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code") + display("http request returned an unsuccessful status code: {}", e) + } + } + }; +} + +#[test] +fn smoke_test_6() { + error_chain! { + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code") + display("http request returned an unsuccessful status code: {}", e) + } + } + }; +} + +#[test] +fn smoke_test_7() { + error_chain! { + types { } + + foreign_links { } + + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code") + display("http request returned an unsuccessful status code: {}", e) + } + } + }; +} + +#[test] +fn smoke_test_8() { + error_chain! { + types { } + + links { } + links { } + + foreign_links { } + foreign_links { } + + errors { + FileNotFound + AccessDenied + } + }; +} + +#[test] +fn order_test_1() { + error_chain! { types { } links { } foreign_links { } errors { } }; +} + +#[test] +fn order_test_2() { + error_chain! { links { } types { } foreign_links { } errors { } }; +} + +#[test] +fn order_test_3() { + error_chain! { foreign_links { } links { } errors { } types { } }; +} + +#[test] +fn order_test_4() { + error_chain! { errors { } types { } foreign_links { } }; +} + +#[test] +fn order_test_5() { + error_chain! { foreign_links { } types { } }; +} + +#[test] +fn order_test_6() { + error_chain! { + links { } + + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code") + display("http request returned an unsuccessful status code: {}", e) + } + } + + + foreign_links { } + }; +} + +#[test] +fn order_test_7() { + error_chain! { + links { } + + foreign_links { } + + types { + Error, ErrorKind, ResultExt, Result; + } + }; +} + + +#[test] +fn order_test_8() { + error_chain! { + links { } + + foreign_links { } + foreign_links { } + + types { + Error, ErrorKind, ResultExt, Result; + } + }; +} + +#[test] +fn empty() { + error_chain!{}; +} + +#[test] +#[cfg(feature = "backtrace")] +fn has_backtrace_depending_on_env() { + use std::process::Command; + use std::path::Path; + + let cmd_path = if cfg!(windows) { + Path::new("./target/debug/has_backtrace.exe") + } else { + Path::new("./target/debug/has_backtrace") + }; + let mut cmd = Command::new(cmd_path); + + // missing RUST_BACKTRACE and RUST_BACKTRACE=0 + cmd.env_remove("RUST_BACKTRACE"); + assert_eq!(cmd.status().unwrap().code().unwrap(), 0); + + cmd.env("RUST_BACKTRACE", "0"); + assert_eq!(cmd.status().unwrap().code().unwrap(), 0); + + // RUST_BACKTRACE set to anything but 0 + cmd.env("RUST_BACKTRACE", "yes"); + assert_eq!(cmd.status().unwrap().code().unwrap(), 1); + + cmd.env("RUST_BACKTRACE", "1"); + assert_eq!(cmd.status().unwrap().code().unwrap(), 1); +} + +#[test] +fn chain_err() { + use std::fmt; + + error_chain! { + foreign_links { + Fmt(fmt::Error); + } + errors { + Test + } + } + + let _: Result<()> = Err(fmt::Error).chain_err(|| ""); + let _: Result<()> = Err(Error::from_kind(ErrorKind::Test)).chain_err(|| ""); +} + +/// Verify that an error chain is extended one by `Error::chain_err`, with +/// the new error added to the end. +#[test] +fn error_chain_err() { + error_chain! { + errors { + Test + } + } + + let base = Error::from(ErrorKind::Test); + let ext = base.chain_err(|| "Test passes"); + + if let Error(ErrorKind::Msg(_), _) = ext { + // pass + } else { + panic!("The error should be wrapped. {:?}", ext); + } +} + +#[test] +fn links() { + mod test { + error_chain!{} + } + + error_chain! { + links { + Test(test::Error, test::ErrorKind); + } + } +} + +#[cfg(test)] +mod foreign_link_test { + + use std::fmt; + + // Note: foreign errors must be `pub` because they appear in the + // signature of the public foreign_link_error_path + #[derive(Debug)] + pub struct ForeignError { + cause: ForeignErrorCause, + } + + impl ::std::error::Error for ForeignError { + fn description(&self) -> &'static str { + "Foreign error description" + } + + fn cause(&self) -> Option<&::std::error::Error> { + Some(&self.cause) + } + } + + impl fmt::Display for ForeignError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "Foreign error display") + } + } + + #[derive(Debug)] + pub struct ForeignErrorCause {} + + impl ::std::error::Error for ForeignErrorCause { + fn description(&self) -> &'static str { + "Foreign error cause description" + } + + fn cause(&self) -> Option<&::std::error::Error> { + None + } + } + + impl fmt::Display for ForeignErrorCause { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "Foreign error cause display") + } + } + + error_chain! { + types{ + Error, ErrorKind, ResultExt, Result; + } + links {} + foreign_links { + Foreign(ForeignError); + Io(::std::io::Error); + } + errors {} + } + + #[test] + fn display_underlying_error() { + let chained_error = try_foreign_error().err().unwrap(); + assert_eq!(format!("{}", ForeignError { cause: ForeignErrorCause {} }), + format!("{}", chained_error)); + } + + #[test] + fn finds_cause() { + let chained_error = try_foreign_error().err().unwrap(); + assert_eq!(format!("{}", ForeignErrorCause {}), + format!("{}", ::std::error::Error::cause(&chained_error).unwrap())); + } + + #[test] + fn iterates() { + let chained_error = try_foreign_error().err().unwrap(); + let mut error_iter = chained_error.iter(); + assert!(!format!("{:?}", error_iter).is_empty()); + assert_eq!(format!("{}", ForeignError { cause: ForeignErrorCause {} }), + format!("{}", error_iter.next().unwrap())); + assert_eq!(format!("{}", ForeignErrorCause {}), + format!("{}", error_iter.next().unwrap())); + assert_eq!(format!("{:?}", None as Option<&::std::error::Error>), + format!("{:?}", error_iter.next())); + } + + fn try_foreign_error() -> Result<()> { + Err(ForeignError { cause: ForeignErrorCause {} })?; + Ok(()) + } +} + +#[cfg(test)] +mod attributes_test { + #[allow(unused_imports)] + use std::io; + + #[cfg(not(test))] + mod inner { + error_chain!{} + } + + error_chain! { + types { + Error, ErrorKind, ResultExt, Result; + } + + links { + Inner(inner::Error, inner::ErrorKind) #[cfg(not(test))]; + } + + foreign_links { + Io(io::Error) #[cfg(not(test))]; + } + + errors { + #[cfg(not(test))] + AnError { + + } + } + } +} + +#[test] +fn with_result() { + error_chain! { + types { + Error, ErrorKind, ResultExt, Result; + } + } + let _: Result<()> = Ok(()); +} + +#[test] +fn without_result() { + error_chain! { + types { + Error, ErrorKind, ResultExt; + } + } + let _: Result<(), ()> = Ok(()); +} + +#[test] +fn documentation() { + mod inner { + error_chain!{} + } + + error_chain! { + links { + Inner(inner::Error, inner::ErrorKind) #[doc = "Doc"]; + } + foreign_links { + Io(::std::io::Error) #[doc = "Doc"]; + } + errors { + /// Doc + Variant + } + } +} + +#[cfg(test)] +mod multiple_error_same_mod { + error_chain! { + types { + MyError, MyErrorKind, MyResultExt, MyResult; + } + } + error_chain!{} +} + +#[doc(test)] +#[deny(dead_code)] +mod allow_dead_code { + error_chain!{} +} + +// Make sure links actually work! +#[test] +fn rustup_regression() { + error_chain! { + links { + Download(error_chain::mock::Error, error_chain::mock::ErrorKind); + } + + foreign_links { } + + errors { + LocatingWorkingDir { + description("could not locate working directory") + } + } + } +} + +#[test] +fn error_patterns() { + error_chain! { + links { } + + foreign_links { } + + errors { } + } + + // Tuples look nice when matching errors + match Error::from("Test") { + Error(ErrorKind::Msg(_), _) => {}, + _ => {}, + } +} + +#[test] +fn error_first() { + error_chain! { + errors { + LocatingWorkingDir { + description("could not locate working directory") + } + } + + links { + Download(error_chain::mock::Error, error_chain::mock::ErrorKind); + } + + foreign_links { } + } +} + +#[test] +fn bail() { + error_chain! { + errors { Foo } + } + + fn foo() -> Result<()> { + bail!(ErrorKind::Foo) + } + + fn bar() -> Result<()> { + bail!("bar") + } + + fn baz() -> Result<()> { + bail!("{}", "baz") + } +} + +#[test] +fn ensure() { + error_chain! { + errors { Bar } + } + + fn foo(x: u8) -> Result<()> { + ensure!(x == 42, ErrorKind::Bar); + Ok(()) + } + + assert!(foo(42).is_ok()); + assert!(foo(0).is_err()); +} + +/// Since the `types` declaration is a list of symbols, check if we +/// don't change their meaning or order. +#[test] +fn types_declarations() { + error_chain! { + types { + MyError, MyErrorKind, MyResultExt, MyResult; + } + } + + MyError::from_kind(MyErrorKind::Msg("".into())); + + let err: Result<(), ::std::io::Error> = Ok(()); + MyResultExt::chain_err(err, || "").unwrap(); + + let _: MyResult<()> = Ok(()); +} + +#[test] +/// Calling chain_err over a `Result` containing an error to get a chained error +/// and constructing a MyError directly, passing it an error should be equivalent. +fn rewrapping() { + + use std::env::VarError::{self, NotPresent, NotUnicode}; + + error_chain! { + foreign_links { + VarErr(VarError); + } + + types { + MyError, MyErrorKind, MyResultExt, MyResult; + } + } + + let result_a_from_func: Result = Err(VarError::NotPresent); + let result_b_from_func: Result = Err(VarError::NotPresent); + + let our_error_a = result_a_from_func.map_err(|e| match e { + NotPresent => MyError::with_chain(e, "env var wasn't provided"), + NotUnicode(_) => MyError::with_chain(e, "env var was bork文字化ã"), + }); + + let our_error_b = result_b_from_func.or_else(|e| match e { + NotPresent => Err(e).chain_err(|| "env var wasn't provided"), + NotUnicode(_) => Err(e).chain_err(|| "env var was bork文字化ã"), + }); + + assert_eq!(format!("{}", our_error_a.unwrap_err()), + format!("{}", our_error_b.unwrap_err())); + +} + +#[test] +fn comma_in_errors_impl() { + error_chain! { + links { } + + foreign_links { } + + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code"), + display("http request returned an unsuccessful status code: {}", e) + } + } + }; +} + + +#[test] +fn trailing_comma_in_errors_impl() { + error_chain! { + links { } + + foreign_links { } + + errors { + HttpStatus(e: u32) { + description("http request returned an unsuccessful status code"), + display("http request returned an unsuccessful status code: {}", e), + } + } + }; +} diff --git a/filetime-0.1.14/.cargo-checksum.json b/filetime-0.1.14/.cargo-checksum.json new file mode 100644 index 000000000..ddb81402b --- /dev/null +++ b/filetime-0.1.14/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"aa75ec8f7927063335a9583e7fa87b0110bb888cf766dc01b54c0ff70d760c8e"} \ No newline at end of file diff --git a/filetime-0.1.14/.travis.yml b/filetime-0.1.14/.travis.yml new file mode 100644 index 000000000..ba7721842 --- /dev/null +++ b/filetime-0.1.14/.travis.yml @@ -0,0 +1,26 @@ +language: rust +rust: + - stable + - beta + - nightly +sudo: false +before_script: + - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH +script: + - cargo build --verbose + - cargo test --verbose + - cargo doc --no-deps +after_success: + - travis-cargo --only nightly doc-upload +env: + global: + secure: "MIaQyJIgy7VUoYHY7KbYtxpN/t+a2eWk8PihYctz+F+1PANgD6KbgbF9JW4ip5MYaehk7UWs++kPkHiAvJFKWo2BnQswc4digTUa9Vc2n8/C0d0Ec2zn1EUXH4fkeaMvIffn8QQUPwuNdE6khifSfG8Y42siqJF4zkuPKwaLrUo=" + + + +notifications: + email: + on_success: never +os: + - linux + - osx diff --git a/filetime-0.1.14/Cargo.toml b/filetime-0.1.14/Cargo.toml new file mode 100644 index 000000000..c4cc50512 --- /dev/null +++ b/filetime-0.1.14/Cargo.toml @@ -0,0 +1,31 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "filetime" +version = "0.1.14" +authors = ["Alex Crichton "] +description = "Platform-agnostic accessors of timestamps in File metadata\n" +homepage = "https://github.com/alexcrichton/filetime" +documentation = "http://alexcrichton.com/filetime" +readme = "README.md" +keywords = ["timestamp", "mtime"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/filetime" +[dependencies.cfg-if] +version = "0.1" +[dev-dependencies.tempdir] +version = "0.3" +[target."cfg(unix)".dependencies.libc] +version = "0.2" +[target."cfg(target_os = \"redox\")".dependencies.redox_syscall] +version = "0.1" diff --git a/filetime-0.1.14/LICENSE-APACHE b/filetime-0.1.14/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/filetime-0.1.14/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/filetime-0.1.14/LICENSE-MIT b/filetime-0.1.14/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/filetime-0.1.14/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/filetime-0.1.14/README.md b/filetime-0.1.14/README.md new file mode 100644 index 000000000..0422084e7 --- /dev/null +++ b/filetime-0.1.14/README.md @@ -0,0 +1,25 @@ +# filetime + +[![Build Status](https://travis-ci.org/alexcrichton/filetime.svg?branch=master)](https://travis-ci.org/alexcrichton/filetime) +[![Build status](https://ci.appveyor.com/api/projects/status/9tatexq47i3ee13k?svg=true)](https://ci.appveyor.com/project/alexcrichton/filetime) + +[Documentation](http://alexcrichton.com/filetime/filetime/index.html) + +A helper library for inspecting the various timestamps of files in Rust. This +library takes into account cross-platform differences in terms of where the +timestamps are located, what they are called, and how to convert them into a +platform-independent representation. + +```toml +# Cargo.toml +[dependencies] +filetime = "0.1" +``` + +# License + +`filetime` is primarily distributed under the terms of both the MIT license and +the Apache License (Version 2.0), with portions covered by various BSD-like +licenses. + +See LICENSE-APACHE, and LICENSE-MIT for details. diff --git a/filetime-0.1.14/appveyor.yml b/filetime-0.1.14/appveyor.yml new file mode 100644 index 000000000..4a6104291 --- /dev/null +++ b/filetime-0.1.14/appveyor.yml @@ -0,0 +1,17 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-gnu +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - SET PATH=%PATH%;C:\MinGW\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --verbose --target %TARGET% diff --git a/filetime-0.1.14/src/lib.rs b/filetime-0.1.14/src/lib.rs new file mode 100644 index 000000000..b9c8afe0c --- /dev/null +++ b/filetime-0.1.14/src/lib.rs @@ -0,0 +1,286 @@ +//! Timestamps for files in Rust +//! +//! This library provides platform-agnostic inspection of the various timestamps +//! present in the standard `fs::Metadata` structure. +//! +//! # Installation +//! +//! Add this to your `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! filetime = "0.1" +//! ``` +//! +//! # Usage +//! +//! ```no_run +//! use std::fs; +//! use filetime::FileTime; +//! +//! let metadata = fs::metadata("foo.txt").unwrap(); +//! +//! let mtime = FileTime::from_last_modification_time(&metadata); +//! println!("{}", mtime); +//! +//! let atime = FileTime::from_last_access_time(&metadata); +//! assert!(mtime < atime); +//! +//! // Inspect values that can be interpreted across platforms +//! println!("{}", mtime.seconds_relative_to_1970()); +//! println!("{}", mtime.nanoseconds()); +//! +//! // Print the platform-specific value of seconds +//! println!("{}", mtime.seconds()); +//! ``` + +#[macro_use] +extern crate cfg_if; + +use std::fmt; +use std::fs; +use std::io; +use std::path::Path; + +cfg_if! { + if #[cfg(target_os = "redox")] { + #[path = "redox.rs"] + mod imp; + } else if #[cfg(windows)] { + #[path = "windows.rs"] + mod imp; + } else { + #[path = "unix/mod.rs"] + mod imp; + } +} + +/// A helper structure to represent a timestamp for a file. +/// +/// The actual value contined within is platform-specific and does not have the +/// same meaning across platforms, but comparisons and stringification can be +/// significant among the same platform. +#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Copy, Clone, Hash)] +pub struct FileTime { + seconds: u64, + nanos: u32, +} + +impl FileTime { + /// Creates a new timestamp representing a 0 time. + /// + /// Useful for creating the base of a cmp::max chain of times. + pub fn zero() -> FileTime { + FileTime { seconds: 0, nanos: 0 } + } + + /// Creates a new instance of `FileTime` with a number of seconds and + /// nanoseconds relative to January 1, 1970. + /// + /// Note that this is typically the relative point that Unix time stamps are + /// from, but on Windows the native time stamp is relative to January 1, + /// 1601 so the return value of `seconds` from the returned `FileTime` + /// instance may not be the same as that passed in. + pub fn from_seconds_since_1970(seconds: u64, nanos: u32) -> FileTime { + FileTime { + seconds: seconds + if cfg!(windows) {11644473600} else {0}, + nanos: nanos, + } + } + + /// Creates a new timestamp from the last modification time listed in the + /// specified metadata. + /// + /// The returned value corresponds to the `mtime` field of `stat` on Unix + /// platforms and the `ftLastWriteTime` field on Windows platforms. + pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { + imp::from_last_modification_time(meta) + } + + /// Creates a new timestamp from the last access time listed in the + /// specified metadata. + /// + /// The returned value corresponds to the `atime` field of `stat` on Unix + /// platforms and the `ftLastAccessTime` field on Windows platforms. + pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { + imp::from_last_access_time(meta) + } + + /// Creates a new timestamp from the creation time listed in the specified + /// metadata. + /// + /// The returned value corresponds to the `birthtime` field of `stat` on + /// Unix platforms and the `ftCreationTime` field on Windows platforms. Note + /// that not all Unix platforms have this field available and may return + /// `None` in some circumstances. + pub fn from_creation_time(meta: &fs::Metadata) -> Option { + imp::from_creation_time(meta) + } + + /// Returns the whole number of seconds represented by this timestamp. + /// + /// Note that this value's meaning is **platform specific**. On Unix + /// platform time stamps are typically relative to January 1, 1970, but on + /// Windows platforms time stamps are relative to January 1, 1601. + pub fn seconds(&self) -> u64 { self.seconds } + + /// Returns the whole number of seconds represented by this timestamp, + /// relative to the Unix epoch start of January 1, 1970. + /// + /// Note that this does not return the same value as `seconds` for Windows + /// platforms as seconds are relative to a different date there. + pub fn seconds_relative_to_1970(&self) -> u64 { + self.seconds - if cfg!(windows) {11644473600} else {0} + } + + /// Returns the nanosecond precision of this timestamp. + /// + /// The returned value is always less than one billion and represents a + /// portion of a second forward from the seconds returned by the `seconds` + /// method. + pub fn nanoseconds(&self) -> u32 { self.nanos } +} + +impl fmt::Display for FileTime { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}.{:09}s", self.seconds, self.nanos) + } +} + +/// Set the last access and modification times for a file on the filesystem. +/// +/// This function will set the `atime` and `mtime` metadata fields for a file +/// on the local filesystem, returning any error encountered. +pub fn set_file_times

(p: P, atime: FileTime, mtime: FileTime) + -> io::Result<()> + where P: AsRef +{ + imp::set_file_times(p.as_ref(), atime, mtime) +} + +/// Set the last access and modification times for a file on the filesystem. +/// This function does not follow symlink. +/// +/// This function will set the `atime` and `mtime` metadata fields for a file +/// on the local filesystem, returning any error encountered. +pub fn set_symlink_file_times

(p: P, atime: FileTime, mtime: FileTime) + -> io::Result<()> + where P: AsRef +{ + imp::set_symlink_file_times(p.as_ref(), atime, mtime) +} + +#[cfg(test)] +mod tests { + extern crate tempdir; + + use std::io; + use std::path::Path; + use std::fs::{self, File}; + use self::tempdir::TempDir; + use super::{FileTime, set_file_times, set_symlink_file_times}; + + #[cfg(unix)] + fn make_symlink(src: P, dst: Q) -> io::Result<()> + where P: AsRef, + Q: AsRef, + { + use std::os::unix::fs::symlink; + symlink(src, dst) + } + + #[cfg(windows)] + fn make_symlink(src: P, dst: Q) -> io::Result<()> + where P: AsRef, + Q: AsRef, + { + use std::os::windows::fs::symlink_file; + symlink_file(src, dst) + } + + #[test] + fn set_file_times_test() { + let td = TempDir::new("filetime").unwrap(); + let path = td.path().join("foo.txt"); + File::create(&path).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + let atime = FileTime::from_last_access_time(&metadata); + set_file_times(&path, atime, mtime).unwrap(); + + let new_mtime = FileTime::from_seconds_since_1970(10_000, 0); + set_file_times(&path, atime, new_mtime).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + + let spath = td.path().join("bar.txt"); + make_symlink(&path, &spath).unwrap(); + let metadata = fs::symlink_metadata(&spath).unwrap(); + let smtime = FileTime::from_last_modification_time(&metadata); + + set_file_times(&spath, atime, mtime).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let cur_mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, cur_mtime); + + let metadata = fs::symlink_metadata(&spath).unwrap(); + let cur_mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(smtime, cur_mtime); + + set_file_times(&spath, atime, new_mtime).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + + let metadata = fs::symlink_metadata(&spath).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, smtime); + } + + #[test] + fn set_symlink_file_times_test() { + let td = TempDir::new("filetime").unwrap(); + let path = td.path().join("foo.txt"); + File::create(&path).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + let atime = FileTime::from_last_access_time(&metadata); + set_symlink_file_times(&path, atime, mtime).unwrap(); + + let new_mtime = FileTime::from_seconds_since_1970(10_000, 0); + set_symlink_file_times(&path, atime, new_mtime).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + + let spath = td.path().join("bar.txt"); + make_symlink(&path, &spath).unwrap(); + + let metadata = fs::symlink_metadata(&spath).unwrap(); + let smtime = FileTime::from_last_modification_time(&metadata); + let satime = FileTime::from_last_access_time(&metadata); + set_symlink_file_times(&spath, smtime, satime).unwrap(); + + let metadata = fs::metadata(&path).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + + let new_smtime = FileTime::from_seconds_since_1970(20_000, 0); + set_symlink_file_times(&spath, atime, new_smtime).unwrap(); + + let metadata = fs::metadata(&spath).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_mtime); + + let metadata = fs::symlink_metadata(&spath).unwrap(); + let mtime = FileTime::from_last_modification_time(&metadata); + assert_eq!(mtime, new_smtime); + } +} diff --git a/filetime-0.1.14/src/redox.rs b/filetime-0.1.14/src/redox.rs new file mode 100644 index 000000000..d4d16d51e --- /dev/null +++ b/filetime-0.1.14/src/redox.rs @@ -0,0 +1,57 @@ +extern crate syscall; + +use std::fs; +use std::io; +use std::os::unix::prelude::*; +use std::path::Path; + +use FileTime; + +pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + let fd = syscall::open(p.as_os_str().as_bytes(), 0) + .map_err(|err| io::Error::from_raw_os_error(err.errno))?; + set_file_times_redox(fd, atime, mtime) +} + +pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + let fd = syscall::open(p.as_os_str().as_bytes(), syscall::O_NOFOLLOW) + .map_err(|err| io::Error::from_raw_os_error(err.errno))?; + set_file_times_redox(fd, atime, mtime) +} + +fn set_file_times_redox(fd: usize, atime: FileTime, mtime: FileTime) -> io::Result<()> { + use self::syscall::TimeSpec; + + fn to_timespec(ft: &FileTime) -> TimeSpec { + TimeSpec { + tv_sec: ft.seconds() as i64, + tv_nsec: ft.nanoseconds() as i32 + } + } + + let times = [to_timespec(&atime), to_timespec(&mtime)]; + let res = syscall::futimens(fd, ×); + let _ = syscall::close(fd); + match res { + Ok(_) => Ok(()), + Err(err) => Err(io::Error::from_raw_os_error(err.errno)) + } +} + +pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { + FileTime { + seconds: meta.mtime() as u64, + nanos: meta.mtime_nsec() as u32, + } +} + +pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { + FileTime { + seconds: meta.atime() as u64, + nanos: meta.atime_nsec() as u32, + } +} + +pub fn from_creation_time(_meta: &fs::Metadata) -> Option { + None +} diff --git a/filetime-0.1.14/src/unix/linux.rs b/filetime-0.1.14/src/unix/linux.rs new file mode 100644 index 000000000..33bd92cc1 --- /dev/null +++ b/filetime-0.1.14/src/unix/linux.rs @@ -0,0 +1,45 @@ +//! On Linux we try to use the more accurate `utimensat` syscall but this isn't +//! always available so we also fall back to `utimes` if we couldn't find +//! `utimensat` at runtime. + +use std::io; +use std::mem; +use std::path::Path; +use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; + +use FileTime; +use super::libc::{self, c_int, c_char, timespec}; + +pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + match utimensat() { + Some(f) => super::utimensat(p, atime, mtime, f, 0), + None => super::utimes(p, atime, mtime, libc::utimes), + } +} + +pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + match utimensat() { + Some(f) => super::utimensat(p, atime, mtime, f, libc::AT_SYMLINK_NOFOLLOW), + None => super::utimes(p, atime, mtime, libc::lutimes), + } +} + +fn utimensat() -> Option c_int> { + static ADDR: AtomicUsize = ATOMIC_USIZE_INIT; + unsafe { + match ADDR.load(Ordering::SeqCst) { + 0 => {} + 1 => return None, + n => return Some(mem::transmute(n)), + } + let name = b"utimensat\0"; + let sym = libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _); + let (val, ret) = if sym.is_null() { + (1, None) + } else { + (sym as usize, Some(mem::transmute(sym))) + }; + ADDR.store(val, Ordering::SeqCst); + return ret + } +} diff --git a/filetime-0.1.14/src/unix/mod.rs b/filetime-0.1.14/src/unix/mod.rs new file mode 100644 index 000000000..e1f7ce4b0 --- /dev/null +++ b/filetime-0.1.14/src/unix/mod.rs @@ -0,0 +1,125 @@ +extern crate libc; + +use std::ffi::CString; +use std::fs; +use std::io; +use std::os::unix::prelude::*; +use std::path::Path; + +use self::libc::{c_int, c_char, timeval, time_t, suseconds_t, c_long}; +use self::libc::{timespec}; + +use FileTime; + +cfg_if! { + if #[cfg(target_os = "linux")] { + mod linux; + pub use self::linux::*; + } else if #[cfg(any(target_os = "android", + target_os = "solaris", + target_os = "netbsd", + target_os = "openbsd"))] { + mod utimensat; + pub use self::utimensat::*; + } else { + mod utimes; + pub use self::utimes::*; + } +} + +#[allow(dead_code)] +fn utimes(p: &Path, + atime: FileTime, + mtime: FileTime, + utimes: unsafe extern fn(*const c_char, *const timeval) -> c_int) + -> io::Result<()> +{ + let times = [to_timeval(&atime), to_timeval(&mtime)]; + let p = try!(CString::new(p.as_os_str().as_bytes())); + return if unsafe { utimes(p.as_ptr() as *const _, times.as_ptr()) == 0 } { + Ok(()) + } else { + Err(io::Error::last_os_error()) + }; + + fn to_timeval(ft: &FileTime) -> timeval { + timeval { + tv_sec: ft.seconds() as time_t, + tv_usec: (ft.nanoseconds() / 1000) as suseconds_t, + } + } +} + +#[allow(dead_code)] +fn utimensat(p: &Path, + atime: FileTime, + mtime: FileTime, + f: unsafe extern fn(c_int, *const c_char, *const timespec, c_int) -> c_int, + flags: c_int) + -> io::Result<()> +{ + let times = [to_timespec(&atime), to_timespec(&mtime)]; + let p = try!(CString::new(p.as_os_str().as_bytes())); + let rc = unsafe { + f(libc::AT_FDCWD, p.as_ptr() as *const _, times.as_ptr(), flags) + }; + return if rc == 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + }; + + fn to_timespec(ft: &FileTime) -> timespec { + timespec { + tv_sec: ft.seconds() as time_t, + tv_nsec: ft.nanoseconds() as c_long, + } + } +} + +pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { + FileTime { + seconds: meta.mtime() as u64, + nanos: meta.mtime_nsec() as u32, + } +} + +pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { + FileTime { + seconds: meta.atime() as u64, + nanos: meta.atime_nsec() as u32, + } +} + +pub fn from_creation_time(meta: &fs::Metadata) -> Option { + macro_rules! birthtim { + ($(($e:expr, $i:ident)),*) => { + #[cfg(any($(target_os = $e),*))] + fn imp(meta: &fs::Metadata) -> Option { + $( + #[cfg(target_os = $e)] + use std::os::$i::fs::MetadataExt; + )* + Some(FileTime { + seconds: meta.st_birthtime() as u64, + nanos: meta.st_birthtime_nsec() as u32, + }) + } + + #[cfg(all($(not(target_os = $e)),*))] + fn imp(_meta: &fs::Metadata) -> Option { + None + } + } + } + + birthtim! { + ("bitrig", bitrig), + ("freebsd", freebsd), + ("ios", ios), + ("macos", macos), + ("openbsd", openbsd) + } + + imp(meta) +} diff --git a/filetime-0.1.14/src/unix/utimensat.rs b/filetime-0.1.14/src/unix/utimensat.rs new file mode 100644 index 000000000..47969fa0f --- /dev/null +++ b/filetime-0.1.14/src/unix/utimensat.rs @@ -0,0 +1,13 @@ +use std::path::Path; +use std::io; + +use FileTime; +use super::libc; + +pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + super::utimensat(p, atime, mtime, libc::utimensat, 0) +} + +pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + super::utimensat(p, atime, mtime, libc::utimensat, libc::AT_SYMLINK_NOFOLLOW) +} diff --git a/filetime-0.1.14/src/unix/utimes.rs b/filetime-0.1.14/src/unix/utimes.rs new file mode 100644 index 000000000..6ec12f76b --- /dev/null +++ b/filetime-0.1.14/src/unix/utimes.rs @@ -0,0 +1,13 @@ +use std::path::Path; +use std::io; + +use FileTime; +use super::libc; + +pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + super::utimes(p, atime, mtime, libc::utimes) +} + +pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + super::utimes(p, atime, mtime, libc::lutimes) +} diff --git a/filetime-0.1.14/src/windows.rs b/filetime-0.1.14/src/windows.rs new file mode 100644 index 000000000..f3eb2bf44 --- /dev/null +++ b/filetime-0.1.14/src/windows.rs @@ -0,0 +1,87 @@ +#![allow(bad_style)] + +use std::fs::{self, OpenOptions}; +use std::io; +use std::os::windows::prelude::*; +use std::path::Path; + +use FileTime; + +pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + set_file_times_w(p, atime, mtime, OpenOptions::new()) +} + +pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { + use std::os::windows::fs::OpenOptionsExt; + const FILE_FLAG_OPEN_REPARSE_POINT: u32 = 0x00200000; + + let mut options = OpenOptions::new(); + options.custom_flags(FILE_FLAG_OPEN_REPARSE_POINT); + set_file_times_w(p, atime, mtime, options) +} + +pub fn set_file_times_w(p: &Path, + atime: FileTime, + mtime: FileTime, + mut options: OpenOptions) -> io::Result<()> { + type BOOL = i32; + type HANDLE = *mut u8; + type DWORD = u32; + + #[repr(C)] + struct FILETIME { + dwLowDateTime: u32, + dwHighDateTime: u32, + } + + extern "system" { + fn SetFileTime(hFile: HANDLE, + lpCreationTime: *const FILETIME, + lpLastAccessTime: *const FILETIME, + lpLastWriteTime: *const FILETIME) -> BOOL; + } + + let f = try!(options.write(true).open(p)); + let atime = to_filetime(&atime); + let mtime = to_filetime(&mtime); + return unsafe { + let ret = SetFileTime(f.as_raw_handle() as *mut _, + 0 as *const _, + &atime, &mtime); + if ret != 0 { + Ok(()) + } else { + Err(io::Error::last_os_error()) + } + }; + + fn to_filetime(ft: &FileTime) -> FILETIME { + let intervals = ft.seconds() * (1_000_000_000 / 100) + + ((ft.nanoseconds() as u64) / 100); + FILETIME { + dwLowDateTime: intervals as DWORD, + dwHighDateTime: (intervals >> 32) as DWORD, + } + } +} + +pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { + from_intervals(meta.last_write_time()) +} + +pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { + from_intervals(meta.last_access_time()) +} + +pub fn from_creation_time(meta: &fs::Metadata) -> Option { + Some(from_intervals(meta.creation_time())) +} + +fn from_intervals(ticks: u64) -> FileTime { + // Windows write times are in 100ns intervals, so do a little math to + // get it into the right representation. + FileTime { + seconds: ticks / (1_000_000_000 / 100), + nanos: ((ticks % (1_000_000_000 / 100)) * 100) as u32, + } +} diff --git a/flate2-0.2.20/.cargo-checksum.json b/flate2-0.2.20/.cargo-checksum.json new file mode 100644 index 000000000..c1b7327bd --- /dev/null +++ b/flate2-0.2.20/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423"} \ No newline at end of file diff --git a/flate2-0.2.20/.travis.yml b/flate2-0.2.20/.travis.yml new file mode 100644 index 000000000..eb722100d --- /dev/null +++ b/flate2-0.2.20/.travis.yml @@ -0,0 +1,32 @@ +language: rust +rust: + - stable + - beta + - nightly +sudo: false +before_script: + - pip install 'travis-cargo<0.2' --user && export PATH=$HOME/.local/bin:$PATH +script: + - export CARGO_TARGET_DIR=`pwd`/target + - cargo build --verbose + - rustdoc --test README.md -L target/debug/deps --extern flate2=target/debug/libflate2.rlib + - cargo test --verbose + - cargo test --verbose --features zlib + - cargo test --verbose --features tokio + - cargo test --verbose --features 'tokio zlib' + - cargo test --verbose --features zlib --no-default-features + - cargo clean && cargo build + - cargo doc --no-deps + - cargo doc --no-deps --manifest-path=miniz-sys/Cargo.toml +after_success: + - travis-cargo --only nightly doc-upload +env: + global: + secure: "PHVT7IaeP5nQQVwGHKwqCYBDp0QyetSlER7se2j2Xgfx+lw3Bu6VWH6VF04B636Gb0tHPN/sUCXSgGRcvDuy6XFOev4LfynoYxNKgHJYg2E34EP2QLwsFfnvE4iujaG3GJk3o935Y7OYGv2OP1HeG4Mv6JhQK0GLnNDBZQ65kWI=" + +notifications: + email: + on_success: never +os: + - linux + - osx diff --git a/flate2-0.2.20/Cargo.toml b/flate2-0.2.20/Cargo.toml new file mode 100644 index 000000000..d1d100bb6 --- /dev/null +++ b/flate2-0.2.20/Cargo.toml @@ -0,0 +1,61 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "flate2" +version = "0.2.20" +authors = ["Alex Crichton "] +description = "Bindings to miniz.c for DEFLATE compression and decompression exposed as\nReader/Writer streams. Contains bindings for zlib, deflate, and gzip-based\nstreams.\n" +homepage = "https://github.com/alexcrichton/flate2-rs" +documentation = "https://docs.rs/flate2" +readme = "README.md" +keywords = ["gzip", "flate", "zlib", "encoding"] +categories = ["compression", "api-bindings"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/flate2-rs" +[dependencies.libc] +version = "0.2" + +[dependencies.libz-sys] +version = "1.0" +optional = true + +[dependencies.miniz-sys] +version = "0.1.7" +optional = true + +[dependencies.futures] +version = "0.1" +optional = true + +[dependencies.tokio-io] +version = "0.1" +optional = true +[dev-dependencies.rand] +version = "0.3" + +[dev-dependencies.quickcheck] +version = "0.4" +default-features = false + +[dev-dependencies.tokio-core] +version = "0.1" + +[features] +default = ["miniz-sys"] +zlib = ["libz-sys"] +tokio = ["tokio-io", "futures"] +[badges.travis-ci] +repository = "alexcrichton/flate2-rs" + +[badges.appveyor] +repository = "alexcrichton/flate2-rs" diff --git a/flate2-0.2.20/LICENSE-APACHE b/flate2-0.2.20/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/flate2-0.2.20/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/flate2-0.2.20/LICENSE-MIT b/flate2-0.2.20/LICENSE-MIT new file mode 100644 index 000000000..39e0ed660 --- /dev/null +++ b/flate2-0.2.20/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 Alex Crichton + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/flate2-0.2.20/README.md b/flate2-0.2.20/README.md new file mode 100644 index 000000000..c8937912f --- /dev/null +++ b/flate2-0.2.20/README.md @@ -0,0 +1,70 @@ +# flate2 + +[![Build Status](https://travis-ci.org/alexcrichton/flate2-rs.svg?branch=master)](https://travis-ci.org/alexcrichton/flate2-rs) +[![Build status](https://ci.appveyor.com/api/projects/status/9tatexq47i3ee13k?svg=true)](https://ci.appveyor.com/project/alexcrichton/flate2-rs) +[![Crates.io](https://img.shields.io/crates/v/flate2.svg?maxAge=2592000)](https://crates.io/crates/flate2) +[![Documentation](https://docs.rs/flate2/badge.svg)](https://docs.rs/flate2) + +A streaming compression/decompression library for Rust. The underlying +implementation by default uses [`miniz`](https://code.google.com/p/miniz/) but +can optionally be configured to use the system zlib, if available. + +Supported formats: + +* deflate +* zlib +* gzip + +```toml +# Cargo.toml +[dependencies] +flate2 = "0.2" +``` + +Using zlib instead of miniz: + +```toml +[dependencies] +flate2 = { version = "0.2", features = ["zlib"], default-features = false } +``` + +## Compression + +```rust +extern crate flate2; + +use std::io::prelude::*; +use flate2::Compression; +use flate2::write::ZlibEncoder; + +fn main() { + let mut e = ZlibEncoder::new(Vec::new(), Compression::Default); + e.write(b"foo"); + e.write(b"bar"); + let compressed_bytes = e.finish(); +} +``` + +## Decompression + +```rust,no_run +extern crate flate2; + +use std::io::prelude::*; +use flate2::read::GzDecoder; + +fn main() { + let mut d = GzDecoder::new("...".as_bytes()).unwrap(); + let mut s = String::new(); + d.read_to_string(&mut s).unwrap(); + println!("{}", s); +} +``` + +# License + +`flate2-rs` is primarily distributed under the terms of both the MIT license and +the Apache License (Version 2.0), with portions covered by various BSD-like +licenses. + +See LICENSE-APACHE, and LICENSE-MIT for details. diff --git a/flate2-0.2.20/appveyor.yml b/flate2-0.2.20/appveyor.yml new file mode 100644 index 000000000..0a140f7bc --- /dev/null +++ b/flate2-0.2.20/appveyor.yml @@ -0,0 +1,24 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: x86_64-pc-windows-gnu + - TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-gnu +install: + - ps: >- + If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') { + $Env:PATH += ';C:\msys64\mingw64\bin' + } ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') { + $Env:PATH += ';C:\MinGW\bin' + } + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - rustc -V + - cargo -V + +build: false + +test_script: + - cargo test --verbose --target %TARGET% + - cargo test --verbose --target %TARGET% --features tokio diff --git a/flate2-0.2.20/examples/deflatedecoder-bufread.rs b/flate2-0.2.20/examples/deflatedecoder-bufread.rs new file mode 100644 index 000000000..117297feb --- /dev/null +++ b/flate2-0.2.20/examples/deflatedecoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::write::DeflateEncoder; +use flate2::bufread::DeflateDecoder; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = DeflateEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Deflate Encoded vector of bytes and returns a string or error +// Here &[u8] implements Read +fn decode_reader(bytes: Vec) -> io::Result { + let mut deflater = DeflateDecoder::new(&bytes[..]); + let mut s = String::new(); + deflater.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2-0.2.20/examples/deflatedecoder-read.rs b/flate2-0.2.20/examples/deflatedecoder-read.rs new file mode 100644 index 000000000..2d2685780 --- /dev/null +++ b/flate2-0.2.20/examples/deflatedecoder-read.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::write::DeflateEncoder; +use flate2::read::DeflateDecoder; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = DeflateEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Deflate Encoded vector of bytes and returns a string or error +// Here &[u8] implements Read +fn decode_reader(bytes: Vec) -> io::Result { + let mut deflater = DeflateDecoder::new(&bytes[..]); + let mut s = String::new(); + deflater.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2-0.2.20/examples/deflatedecoder-write.rs b/flate2-0.2.20/examples/deflatedecoder-write.rs new file mode 100644 index 000000000..46791e623 --- /dev/null +++ b/flate2-0.2.20/examples/deflatedecoder-write.rs @@ -0,0 +1,26 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::write::DeflateEncoder; +use flate2::write::DeflateDecoder; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = DeflateEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Deflate Encoded vector of bytes and returns a string or error +// Here Vec implements Write +fn decode_reader(bytes: Vec) -> io::Result { + let mut writer = Vec::new(); + let mut deflater = DeflateDecoder::new(writer); + deflater.write(&bytes[..])?; + writer = deflater.finish()?; + let return_string = String::from_utf8(writer).expect("String parsing error"); + Ok(return_string) +} diff --git a/flate2-0.2.20/examples/deflateencoder-bufread.rs b/flate2-0.2.20/examples/deflateencoder-bufread.rs new file mode 100644 index 000000000..4ec2ed1c7 --- /dev/null +++ b/flate2-0.2.20/examples/deflateencoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::bufread::DeflateEncoder; +use std::fs::File; +use std::io::BufReader; + +// Open file and debug print the contents compressed with Deflate +fn main() { + println!("{:?}", open_hello_world().unwrap()); +} + +// Opens sample file, compresses the contents and returns a Vector or error +// File wrapped in a BufReader implements Bufread +fn open_hello_world() -> io::Result> { + let f = File::open("examples/hello_world.txt")?; + let b = BufReader::new(f); + let mut deflater = DeflateEncoder::new(b, Compression::Fast); + let mut buffer = Vec::new(); + deflater.read_to_end(&mut buffer)?; + Ok(buffer) +} diff --git a/flate2-0.2.20/examples/deflateencoder-read.rs b/flate2-0.2.20/examples/deflateencoder-read.rs new file mode 100644 index 000000000..bf1bcc6a6 --- /dev/null +++ b/flate2-0.2.20/examples/deflateencoder-read.rs @@ -0,0 +1,20 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::read::DeflateEncoder; + +// Print the Deflate compressed representation of hello world +fn main() { + println!("{:?}", deflateencoder_read_hello_world().unwrap()); +} + +// Return a vector containing the Defalte compressed version of hello world +fn deflateencoder_read_hello_world() -> io::Result> { + let mut ret_vec = [0;100]; + let c = b"hello world"; + let mut deflater = DeflateEncoder::new(&c[..], Compression::Fast); + let count = deflater.read(&mut ret_vec)?; + Ok(ret_vec[0..count].to_vec()) +} diff --git a/flate2-0.2.20/examples/deflateencoder-write.rs b/flate2-0.2.20/examples/deflateencoder-write.rs new file mode 100644 index 000000000..f511aec4b --- /dev/null +++ b/flate2-0.2.20/examples/deflateencoder-write.rs @@ -0,0 +1,12 @@ +extern crate flate2; + +use std::io::prelude::*; +use flate2::Compression; +use flate2::write::DeflateEncoder; + +// Vec implements Write to print the compressed bytes of sample string +fn main() { + let mut e = DeflateEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + println!("{:?}", e.finish().unwrap()); +} diff --git a/flate2-0.2.20/examples/flatereadext.rs b/flate2-0.2.20/examples/flatereadext.rs new file mode 100644 index 000000000..a3a9b0444 --- /dev/null +++ b/flate2-0.2.20/examples/flatereadext.rs @@ -0,0 +1,22 @@ +extern crate flate2; + +use flate2::{FlateReadExt, Compression}; +use std::io::prelude::*; +use std::io; +use std::fs::File; + +fn main() { + println!("{}", run().unwrap()); +} + +fn run() -> io::Result { + let f = File::open("examples/hello_world.txt")?; + + //gz_encode method comes from FlateReadExt and applies to a std::fs::File + let data = f.gz_encode(Compression::Default); + let mut buffer = String::new(); + + //gz_decode method comes from FlateReadExt and applies to a &[u8] + &data.gz_decode()?.read_to_string(&mut buffer)?; + Ok(buffer) +} diff --git a/flate2-0.2.20/examples/gzbuilder.rs b/flate2-0.2.20/examples/gzbuilder.rs new file mode 100644 index 000000000..a61a03f4f --- /dev/null +++ b/flate2-0.2.20/examples/gzbuilder.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use std::fs::File; +use flate2::GzBuilder; +use flate2::Compression; + +// Open file and debug print the contents compressed with gzip +fn main() { + sample_builder().unwrap(); +} + +// GzBuilder opens a file and writes a sample string using Builder pattern +fn sample_builder() -> Result<(), io::Error> { + let f = File::create("examples/hello_world.gz")?; + let mut gz = GzBuilder::new() + .filename("hello_world.txt") + .comment("test file, please delete") + .write(f, Compression::Default); + gz.write(b"hello world")?; + gz.finish()?; + Ok(()) +} diff --git a/flate2-0.2.20/examples/gzdecoder-bufread.rs b/flate2-0.2.20/examples/gzdecoder-bufread.rs new file mode 100644 index 000000000..77f325194 --- /dev/null +++ b/flate2-0.2.20/examples/gzdecoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::write::GzEncoder; +use flate2::bufread::GzDecoder; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = GzEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Gz Encoded vector of bytes and returns a string or error +// Here &[u8] implements BufRead +fn decode_reader(bytes: Vec) -> io::Result { + let mut gz = GzDecoder::new(&bytes[..])?; + let mut s = String::new(); + gz.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2-0.2.20/examples/gzdecoder-read.rs b/flate2-0.2.20/examples/gzdecoder-read.rs new file mode 100644 index 000000000..843d7bd6a --- /dev/null +++ b/flate2-0.2.20/examples/gzdecoder-read.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::write::GzEncoder; +use flate2::read::GzDecoder; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = GzEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Gz Encoded vector of bytes and returns a string or error +// Here &[u8] implements Read +fn decode_reader(bytes: Vec) -> io::Result { + let mut gz = GzDecoder::new(&bytes[..])?; + let mut s = String::new(); + gz.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2-0.2.20/examples/gzencoder-bufread.rs b/flate2-0.2.20/examples/gzencoder-bufread.rs new file mode 100644 index 000000000..8b320d813 --- /dev/null +++ b/flate2-0.2.20/examples/gzencoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::bufread::GzEncoder; +use std::fs::File; +use std::io::BufReader; + +// Open file and debug print the contents compressed with gzip +fn main() { + println!("{:?}", open_hello_world().unwrap()); +} + +// Opens sample file, compresses the contents and returns a Vector or error +// File wrapped in a BufReader implements Bufread +fn open_hello_world() -> io::Result> { + let f = File::open("examples/hello_world.txt")?; + let b = BufReader::new(f); + let mut gz = GzEncoder::new(b, Compression::Fast); + let mut buffer = Vec::new(); + gz.read_to_end(&mut buffer)?; + Ok(buffer) +} diff --git a/flate2-0.2.20/examples/gzencoder-read.rs b/flate2-0.2.20/examples/gzencoder-read.rs new file mode 100644 index 000000000..65dd26bc4 --- /dev/null +++ b/flate2-0.2.20/examples/gzencoder-read.rs @@ -0,0 +1,20 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::read::GzEncoder; + +// Print the GZ compressed representation of hello world +fn main() { + println!("{:?}", gzencoder_read_hello_world().unwrap()); +} + +// Return a vector containing the GZ compressed version of hello world +fn gzencoder_read_hello_world() -> io::Result> { + let mut ret_vec = [0;100]; + let c = b"hello world"; + let mut z = GzEncoder::new(&c[..], Compression::Fast); + let count = z.read(&mut ret_vec)?; + Ok(ret_vec[0..count].to_vec()) +} diff --git a/flate2-0.2.20/examples/gzencoder-write.rs b/flate2-0.2.20/examples/gzencoder-write.rs new file mode 100644 index 000000000..b423b5241 --- /dev/null +++ b/flate2-0.2.20/examples/gzencoder-write.rs @@ -0,0 +1,12 @@ +extern crate flate2; + +use std::io::prelude::*; +use flate2::Compression; +use flate2::write::GzEncoder; + +// Vec implements Write to print the compressed bytes of sample string +fn main() { + let mut e = GzEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + println!("{:?}", e.finish().unwrap()); +} diff --git a/flate2-0.2.20/examples/gzmultidecoder-bufread.rs b/flate2-0.2.20/examples/gzmultidecoder-bufread.rs new file mode 100644 index 000000000..d5db3673e --- /dev/null +++ b/flate2-0.2.20/examples/gzmultidecoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::write::GzEncoder; +use flate2::bufread::MultiGzDecoder; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = GzEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Gz Encoded vector of bytes and returns a string or error +// Here &[u8] implements BufRead +fn decode_reader(bytes: Vec) -> io::Result { + let mut gz = MultiGzDecoder::new(&bytes[..])?; + let mut s = String::new(); + gz.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2-0.2.20/examples/gzmultidecoder-read.rs b/flate2-0.2.20/examples/gzmultidecoder-read.rs new file mode 100644 index 000000000..9263292c9 --- /dev/null +++ b/flate2-0.2.20/examples/gzmultidecoder-read.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::write::GzEncoder; +use flate2::read::MultiGzDecoder; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = GzEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Gz Encoded vector of bytes and returns a string or error +// Here &[u8] implements Read +fn decode_reader(bytes: Vec) -> io::Result { + let mut gz = MultiGzDecoder::new(&bytes[..])?; + let mut s = String::new(); + gz.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2-0.2.20/examples/hello_world.txt b/flate2-0.2.20/examples/hello_world.txt new file mode 100644 index 000000000..557db03de --- /dev/null +++ b/flate2-0.2.20/examples/hello_world.txt @@ -0,0 +1 @@ +Hello World diff --git a/flate2-0.2.20/examples/zlibdecoder-bufread.rs b/flate2-0.2.20/examples/zlibdecoder-bufread.rs new file mode 100644 index 000000000..7216f801e --- /dev/null +++ b/flate2-0.2.20/examples/zlibdecoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::write::ZlibEncoder; +use flate2::bufread::ZlibDecoder; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = ZlibEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_bufreader(bytes).unwrap()); +} + +// Uncompresses a Zlib Encoded vector of bytes and returns a string or error +// Here &[u8] implements BufRead +fn decode_bufreader(bytes: Vec) -> io::Result { + let mut z = ZlibDecoder::new(&bytes[..]); + let mut s = String::new(); + z.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2-0.2.20/examples/zlibdecoder-read.rs b/flate2-0.2.20/examples/zlibdecoder-read.rs new file mode 100644 index 000000000..ab82413fb --- /dev/null +++ b/flate2-0.2.20/examples/zlibdecoder-read.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::write::ZlibEncoder; +use flate2::read::ZlibDecoder; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = ZlibEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Zlib Encoded vector of bytes and returns a string or error +// Here &[u8] implements Read +fn decode_reader(bytes: Vec) -> io::Result { + let mut z = ZlibDecoder::new(&bytes[..]); + let mut s = String::new(); + z.read_to_string(&mut s)?; + Ok(s) +} diff --git a/flate2-0.2.20/examples/zlibdecoder-write.rs b/flate2-0.2.20/examples/zlibdecoder-write.rs new file mode 100644 index 000000000..c70ded3c1 --- /dev/null +++ b/flate2-0.2.20/examples/zlibdecoder-write.rs @@ -0,0 +1,26 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::write::ZlibEncoder; +use flate2::write::ZlibDecoder; + +// Compress a sample string and print it after transformation. +fn main() { + let mut e = ZlibEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + let bytes = e.finish().unwrap(); + println!("{}", decode_reader(bytes).unwrap()); +} + +// Uncompresses a Zlib Encoded vector of bytes and returns a string or error +// Here Vec implements Write +fn decode_reader(bytes: Vec) -> io::Result { + let mut writer = Vec::new(); + let mut z = ZlibDecoder::new(writer); + z.write(&bytes[..])?; + writer = z.finish()?; + let return_string = String::from_utf8(writer).expect("String parsing error"); + Ok(return_string) +} diff --git a/flate2-0.2.20/examples/zlibencoder-bufread.rs b/flate2-0.2.20/examples/zlibencoder-bufread.rs new file mode 100644 index 000000000..39d93611a --- /dev/null +++ b/flate2-0.2.20/examples/zlibencoder-bufread.rs @@ -0,0 +1,24 @@ +extern crate flate2; + +use std::io::prelude::*; +use std::io; +use flate2::Compression; +use flate2::bufread::ZlibEncoder; +use std::fs::File; +use std::io::BufReader; + +// Open file and debug print the contents compressed with zlib +fn main() { + println!("{:?}", open_hello_world().unwrap()); +} + +// Opens sample file, compresses the contents and returns a Vector or error +// File wrapped in a BufReader implements Bufread +fn open_hello_world() -> io::Result> { + let f = File::open("examples/hello_world.txt")?; + let b = BufReader::new(f); + let mut z = ZlibEncoder::new(b, Compression::Fast); + let mut buffer = Vec::new(); + z.read_to_end(&mut buffer)?; + Ok(buffer) +} diff --git a/flate2-0.2.20/examples/zlibencoder-read.rs b/flate2-0.2.20/examples/zlibencoder-read.rs new file mode 100644 index 000000000..3aef92ca4 --- /dev/null +++ b/flate2-0.2.20/examples/zlibencoder-read.rs @@ -0,0 +1,21 @@ +extern crate flate2; + +use std::io::prelude::*; +use flate2::Compression; +use flate2::read::ZlibEncoder; +use std::fs::File; + +// Open file and debug print the compressed contents +fn main() { + println!("{:?}", open_hello_world().unwrap()); +} + +// Opens sample file, compresses the contents and returns a Vector or error +// File implements Read +fn open_hello_world() -> std::io::Result> { + let f = File::open("examples/hello_world.txt")?; + let mut z = ZlibEncoder::new(f, Compression::Fast); + let mut buffer = [0;50]; + let byte_count = z.read(&mut buffer)?; + Ok(buffer[0..byte_count].to_vec()) +} diff --git a/flate2-0.2.20/examples/zlibencoder-write.rs b/flate2-0.2.20/examples/zlibencoder-write.rs new file mode 100644 index 000000000..9152b30ea --- /dev/null +++ b/flate2-0.2.20/examples/zlibencoder-write.rs @@ -0,0 +1,12 @@ +extern crate flate2; + +use std::io::prelude::*; +use flate2::Compression; +use flate2::write::ZlibEncoder; + +// Vec implements Write to print the compressed bytes of sample string +fn main() { + let mut e = ZlibEncoder::new(Vec::new(), Compression::Default); + e.write(b"Hello World").unwrap(); + println!("{:?}", e.finish().unwrap()); +} diff --git a/flate2-0.2.20/src/bufreader.rs b/flate2-0.2.20/src/bufreader.rs new file mode 100644 index 000000000..a4bd8c796 --- /dev/null +++ b/flate2-0.2.20/src/bufreader.rs @@ -0,0 +1,98 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cmp; +use std::io; +use std::io::prelude::*; +use std::mem; + +pub struct BufReader { + inner: R, + buf: Box<[u8]>, + pos: usize, + cap: usize, +} + +impl ::std::fmt::Debug for BufReader where R: ::std::fmt::Debug { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error>{ + fmt.debug_struct("BufReader") + .field("reader", &self.inner) + .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) + .finish() + } +} + +impl BufReader { + pub fn new(inner: R) -> BufReader { + BufReader::with_buf(vec![0; 32 * 1024], inner) + } + + pub fn with_buf(buf: Vec, inner: R) -> BufReader { + BufReader { + inner: inner, + buf: buf.into_boxed_slice(), + pos: 0, + cap: 0, + } + } +} + +impl BufReader { + pub fn get_ref(&self) -> &R { + &self.inner + } + + pub fn get_mut(&mut self) -> &mut R { + &mut self.inner + } + + pub fn into_inner(self) -> R { + self.inner + } + + pub fn reset(&mut self, inner: R) -> R { + self.pos = 0; + self.cap = 0; + mem::replace(&mut self.inner, inner) + } +} + +impl Read for BufReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // If we don't have any buffered data and we're doing a massive read + // (larger than our internal buffer), bypass our internal buffer + // entirely. + if self.pos == self.cap && buf.len() >= self.buf.len() { + return self.inner.read(buf); + } + let nread = { + let mut rem = try!(self.fill_buf()); + try!(rem.read(buf)) + }; + self.consume(nread); + Ok(nread) + } +} + +impl BufRead for BufReader { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the underlying reader. + if self.pos == self.cap { + self.cap = try!(self.inner.read(&mut self.buf)); + self.pos = 0; + } + Ok(&self.buf[self.pos..self.cap]) + } + + fn consume(&mut self, amt: usize) { + self.pos = cmp::min(self.pos + amt, self.cap); + } +} diff --git a/flate2-0.2.20/src/crc.rs b/flate2-0.2.20/src/crc.rs new file mode 100644 index 000000000..c6e93ac1f --- /dev/null +++ b/flate2-0.2.20/src/crc.rs @@ -0,0 +1,124 @@ +//! Simple CRC bindings backed by miniz.c + +use std::io::prelude::*; +use std::io; +use libc; + +use ffi; + +/// The CRC calculated by a [`CrcReader`]. +/// +/// [`CrcReader`]: struct.CrcReader.html +#[derive(Debug)] +pub struct Crc { + crc: libc::c_ulong, + amt: u32, +} + +/// A wrapper around a [`Read`] that calculates the CRC. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +#[derive(Debug)] +pub struct CrcReader { + inner: R, + crc: Crc, +} + +impl Crc { + /// Create a new CRC. + pub fn new() -> Crc { + Crc { crc: 0, amt: 0 } + } + + /// bla + pub fn sum(&self) -> u32 { + self.crc as u32 + } + + /// The number of bytes that have been used to calculate the CRC. + /// This value is only accurate if the amount is lower than 2^32. + pub fn amount(&self) -> u32 { + self.amt + } + + /// Update the CRC with the bytes in `data`. + pub fn update(&mut self, data: &[u8]) { + self.amt = self.amt.wrapping_add(data.len() as u32); + self.crc = unsafe { + ffi::mz_crc32(self.crc, data.as_ptr(), data.len() as libc::size_t) + }; + } + + /// Reset the CRC. + pub fn reset(&mut self) { + self.crc = 0; + self.amt = 0; + } + + /// Combine the CRC with the CRC for the subsequent block of bytes. + pub fn combine(&mut self, additional_crc: &Crc) { + self.crc = unsafe { + ffi::mz_crc32_combine(self.crc as ::libc::c_ulong, + additional_crc.crc as ::libc::c_ulong, + additional_crc.amt as ::libc::off_t) + }; + self.amt += additional_crc.amt; + } +} + +impl CrcReader { + /// Create a new CrcReader. + pub fn new(r: R) -> CrcReader { + CrcReader { + inner: r, + crc: Crc::new(), + } + } +} + +impl CrcReader { + /// Get the Crc for this CrcReader. + pub fn crc(&self) -> &Crc { + &self.crc + } + + /// Get the reader that is wrapped by this CrcReader. + pub fn into_inner(self) -> R { + self.inner + } + + /// Get the reader that is wrapped by this CrcReader by reference. + pub fn get_ref(&self) -> &R { + &self.inner + } + + /// Get a mutable reference to the reader that is wrapped by this CrcReader. + pub fn get_mut(&mut self) -> &mut R { + &mut self.inner + } + + /// Reset the Crc in this CrcReader. + pub fn reset(&mut self) { + self.crc.reset(); + } +} + +impl Read for CrcReader { + fn read(&mut self, into: &mut [u8]) -> io::Result { + let amt = try!(self.inner.read(into)); + self.crc.update(&into[..amt]); + Ok(amt) + } +} + +impl BufRead for CrcReader { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + self.inner.fill_buf() + } + fn consume(&mut self, amt: usize) { + if let Ok(data) = self.inner.fill_buf() { + self.crc.update(&data[..amt]); + } + self.inner.consume(amt); + } +} diff --git a/flate2-0.2.20/src/deflate/bufread.rs b/flate2-0.2.20/src/deflate/bufread.rs new file mode 100644 index 000000000..9a9a47ec6 --- /dev/null +++ b/flate2-0.2.20/src/deflate/bufread.rs @@ -0,0 +1,269 @@ +use std::io::prelude::*; +use std::io; +use std::mem; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use zio; +use {Compress, Decompress}; + +/// A DEFLATE encoder, or compressor. +/// +/// This structure implements a [`BufRead`] interface and will read uncompressed +/// data from an underlying stream and emit a stream of compressed data. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// use flate2::Compression; +/// use flate2::bufread::DeflateEncoder; +/// use std::fs::File; +/// use std::io::BufReader; +/// +/// # fn main() { +/// # println!("{:?}", open_hello_world().unwrap()); +/// # } +/// # +/// // Opens sample file, compresses the contents and returns a Vector +/// fn open_hello_world() -> io::Result> { +/// let f = File::open("examples/hello_world.txt")?; +/// let b = BufReader::new(f); +/// let mut deflater = DeflateEncoder::new(b, Compression::Fast); +/// let mut buffer = Vec::new(); +/// deflater.read_to_end(&mut buffer)?; +/// Ok(buffer) +/// } +/// ``` +#[derive(Debug)] +pub struct DeflateEncoder { + obj: R, + data: Compress, +} + + +impl DeflateEncoder { + /// Creates a new encoder which will read uncompressed data from the given + /// stream and emit the compressed stream. + pub fn new(r: R, level: ::Compression) -> DeflateEncoder { + DeflateEncoder { + obj: r, + data: Compress::new(level, false), + } + } +} + +pub fn reset_encoder_data(zlib: &mut DeflateEncoder) { + zlib.data.reset(); +} + +impl DeflateEncoder { + /// Resets the state of this encoder entirely, swapping out the input + /// stream for another. + /// + /// This function will reset the internal state of this encoder and replace + /// the input stream with the one provided, returning the previous input + /// stream. Future data read from this encoder will be the compressed + /// version of `r`'s data. + pub fn reset(&mut self, r: R) -> R { + reset_encoder_data(self); + mem::replace(&mut self.obj, r) + } + + /// Acquires a reference to the underlying reader + pub fn get_ref(&self) -> &R { + &self.obj + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + &mut self.obj + } + + /// Consumes this encoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.obj + } + + /// Returns the number of bytes that have been read into this compressor. + /// + /// Note that not all bytes read from the underlying object may be accounted + /// for, there may still be some active buffering. + pub fn total_in(&self) -> u64 { + self.data.total_in() + } + + /// Returns the number of bytes that the compressor has produced. + /// + /// Note that not all bytes may have been read yet, some may still be + /// buffered. + pub fn total_out(&self) -> u64 { + self.data.total_out() + } +} + +impl Read for DeflateEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + zio::read(&mut self.obj, &mut self.data, buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for DeflateEncoder {} + +impl Write for DeflateEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for DeflateEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} + +/// A DEFLATE decoder, or decompressor. +/// +/// This structure implements a [`BufRead`] interface and takes a stream of +/// compressed data as input, providing the decompressed data when read from. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::DeflateEncoder; +/// use flate2::bufread::DeflateDecoder; +/// +/// # fn main() { +/// # let mut e = DeflateEncoder::new(Vec::new(), Compression::Default); +/// # e.write(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// // Uncompresses a Deflate Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements Read +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut deflater = DeflateDecoder::new(&bytes[..]); +/// let mut s = String::new(); +/// deflater.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct DeflateDecoder { + obj: R, + data: Decompress, +} + +pub fn reset_decoder_data(zlib: &mut DeflateDecoder) { + zlib.data = Decompress::new(false); +} + +impl DeflateDecoder { + /// Creates a new decoder which will decompress data read from the given + /// stream. + pub fn new(r: R) -> DeflateDecoder { + DeflateDecoder { + obj: r, + data: Decompress::new(false), + } + } +} + +impl DeflateDecoder { + /// Resets the state of this decoder entirely, swapping out the input + /// stream for another. + /// + /// This will reset the internal state of this decoder and replace the + /// input stream with the one provided, returning the previous input + /// stream. Future data read from this decoder will be the decompressed + /// version of `r`'s data. + pub fn reset(&mut self, r: R) -> R { + reset_decoder_data(self); + mem::replace(&mut self.obj, r) + } + + /// Resets the state of this decoder's data + /// + /// This will reset the internal state of this decoder. It will continue + /// reading from the same stream. + pub fn reset_data(&mut self) { + reset_decoder_data(self); + } + + /// Acquires a reference to the underlying stream + pub fn get_ref(&self) -> &R { + &self.obj + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + &mut self.obj + } + + /// Consumes this decoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.obj + } + + /// Returns the number of bytes that the decompressor has consumed. + /// + /// Note that this will likely be smaller than what the decompressor + /// actually read from the underlying stream due to buffering. + pub fn total_in(&self) -> u64 { + self.data.total_in() + } + + /// Returns the number of bytes that the decompressor has produced. + pub fn total_out(&self) -> u64 { + self.data.total_out() + } +} + +impl Read for DeflateDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + zio::read(&mut self.obj, &mut self.data, into) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for DeflateDecoder {} + +impl Write for DeflateDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for DeflateDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} diff --git a/flate2-0.2.20/src/deflate/mod.rs b/flate2-0.2.20/src/deflate/mod.rs new file mode 100644 index 000000000..7bacfa7c8 --- /dev/null +++ b/flate2-0.2.20/src/deflate/mod.rs @@ -0,0 +1,198 @@ +pub mod bufread; +pub mod read; +pub mod write; + +#[cfg(test)] +mod tests { + use std::io::prelude::*; + + use rand::{thread_rng, Rng}; + + use super::{read, write}; + use Compression::Default; + + #[test] + fn roundtrip() { + let mut real = Vec::new(); + let mut w = write::DeflateEncoder::new(Vec::new(), Default); + let v = thread_rng().gen_iter::().take(1024).collect::>(); + for _ in 0..200 { + let to_write = &v[..thread_rng().gen_range(0, v.len())]; + real.extend(to_write.iter().map(|x| *x)); + w.write_all(to_write).unwrap(); + } + let result = w.finish().unwrap(); + let mut r = read::DeflateDecoder::new(&result[..]); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert!(ret == real); + } + + #[test] + fn drop_writes() { + let mut data = Vec::new(); + write::DeflateEncoder::new(&mut data, Default) + .write_all(b"foo") + .unwrap(); + let mut r = read::DeflateDecoder::new(&data[..]); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert!(ret == b"foo"); + } + + #[test] + fn total_in() { + let mut real = Vec::new(); + let mut w = write::DeflateEncoder::new(Vec::new(), Default); + let v = thread_rng().gen_iter::().take(1024).collect::>(); + for _ in 0..200 { + let to_write = &v[..thread_rng().gen_range(0, v.len())]; + real.extend(to_write.iter().map(|x| *x)); + w.write_all(to_write).unwrap(); + } + let mut result = w.finish().unwrap(); + + let result_len = result.len(); + + for _ in 0..200 { + result.extend(v.iter().map(|x| *x)); + } + + let mut r = read::DeflateDecoder::new(&result[..]); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert!(ret == real); + assert_eq!(r.total_in(), result_len as u64); + } + + #[test] + fn roundtrip2() { + let v = thread_rng() + .gen_iter::() + .take(1024 * 1024) + .collect::>(); + let mut r = read::DeflateDecoder::new(read::DeflateEncoder::new(&v[..], Default)); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert_eq!(ret, v); + } + + #[test] + fn roundtrip3() { + let v = thread_rng() + .gen_iter::() + .take(1024 * 1024) + .collect::>(); + let mut w = write::DeflateEncoder::new(write::DeflateDecoder::new(Vec::new()), Default); + w.write_all(&v).unwrap(); + let w = w.finish().unwrap().finish().unwrap(); + assert!(w == v); + } + + #[test] + fn reset_writer() { + let v = thread_rng() + .gen_iter::() + .take(1024 * 1024) + .collect::>(); + let mut w = write::DeflateEncoder::new(Vec::new(), Default); + w.write_all(&v).unwrap(); + let a = w.reset(Vec::new()).unwrap(); + w.write_all(&v).unwrap(); + let b = w.finish().unwrap(); + + let mut w = write::DeflateEncoder::new(Vec::new(), Default); + w.write_all(&v).unwrap(); + let c = w.finish().unwrap(); + assert!(a == b && b == c); + } + + #[test] + fn reset_reader() { + let v = thread_rng() + .gen_iter::() + .take(1024 * 1024) + .collect::>(); + let (mut a, mut b, mut c) = (Vec::new(), Vec::new(), Vec::new()); + let mut r = read::DeflateEncoder::new(&v[..], Default); + r.read_to_end(&mut a).unwrap(); + r.reset(&v[..]); + r.read_to_end(&mut b).unwrap(); + + let mut r = read::DeflateEncoder::new(&v[..], Default); + r.read_to_end(&mut c).unwrap(); + assert!(a == b && b == c); + } + + #[test] + fn reset_decoder() { + let v = thread_rng() + .gen_iter::() + .take(1024 * 1024) + .collect::>(); + let mut w = write::DeflateEncoder::new(Vec::new(), Default); + w.write_all(&v).unwrap(); + let data = w.finish().unwrap(); + + { + let (mut a, mut b, mut c) = (Vec::new(), Vec::new(), Vec::new()); + let mut r = read::DeflateDecoder::new(&data[..]); + r.read_to_end(&mut a).unwrap(); + r.reset(&data); + r.read_to_end(&mut b).unwrap(); + + let mut r = read::DeflateDecoder::new(&data[..]); + r.read_to_end(&mut c).unwrap(); + assert!(a == b && b == c && c == v); + } + + { + let mut w = write::DeflateDecoder::new(Vec::new()); + w.write_all(&data).unwrap(); + let a = w.reset(Vec::new()).unwrap(); + w.write_all(&data).unwrap(); + let b = w.finish().unwrap(); + + let mut w = write::DeflateDecoder::new(Vec::new()); + w.write_all(&data).unwrap(); + let c = w.finish().unwrap(); + assert!(a == b && b == c && c == v); + } + } + + #[test] + fn zero_length_read_with_data() { + let m = vec![3u8; 128 * 1024 + 1]; + let mut c = read::DeflateEncoder::new(&m[..], ::Compression::Default); + + let mut result = Vec::new(); + c.read_to_end(&mut result).unwrap(); + + let mut d = read::DeflateDecoder::new(&result[..]); + let mut data = Vec::new(); + assert!(d.read(&mut data).unwrap() == 0); + } + + #[test] + fn qc_reader() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(v: Vec) -> bool { + let mut r = read::DeflateDecoder::new(read::DeflateEncoder::new(&v[..], Default)); + let mut v2 = Vec::new(); + r.read_to_end(&mut v2).unwrap(); + v == v2 + } + } + + #[test] + fn qc_writer() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(v: Vec) -> bool { + let mut w = write::DeflateEncoder::new(write::DeflateDecoder::new(Vec::new()), Default); + w.write_all(&v).unwrap(); + v == w.finish().unwrap().finish().unwrap() + } + } +} diff --git a/flate2-0.2.20/src/deflate/read.rs b/flate2-0.2.20/src/deflate/read.rs new file mode 100644 index 000000000..e2363c9cc --- /dev/null +++ b/flate2-0.2.20/src/deflate/read.rs @@ -0,0 +1,268 @@ +use std::io::prelude::*; +use std::io; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use bufreader::BufReader; +use super::bufread; + +/// A DEFLATE encoder, or compressor. +/// +/// This structure implements a [`Read`] interface and will read uncompressed +/// data from an underlying stream and emit a stream of compressed data. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// use flate2::Compression; +/// use flate2::read::DeflateEncoder; +/// +/// # fn main() { +/// # println!("{:?}", deflateencoder_read_hello_world().unwrap()); +/// # } +/// # +/// // Return a vector containing the Deflate compressed version of hello world +/// fn deflateencoder_read_hello_world() -> io::Result> { +/// let mut ret_vec = [0;100]; +/// let c = b"hello world"; +/// let mut deflater = DeflateEncoder::new(&c[..], Compression::Fast); +/// let count = deflater.read(&mut ret_vec)?; +/// Ok(ret_vec[0..count].to_vec()) +/// } +/// ``` +#[derive(Debug)] +pub struct DeflateEncoder { + inner: bufread::DeflateEncoder>, +} + +impl DeflateEncoder { + /// Creates a new encoder which will read uncompressed data from the given + /// stream and emit the compressed stream. + pub fn new(r: R, level: ::Compression) -> DeflateEncoder { + DeflateEncoder { + inner: bufread::DeflateEncoder::new(BufReader::new(r), level), + } + } +} + +impl DeflateEncoder { + /// Resets the state of this encoder entirely, swapping out the input + /// stream for another. + /// + /// This function will reset the internal state of this encoder and replace + /// the input stream with the one provided, returning the previous input + /// stream. Future data read from this encoder will be the compressed + /// version of `r`'s data. + /// + /// Note that there may be currently buffered data when this function is + /// called, and in that case the buffered data is discarded. + pub fn reset(&mut self, r: R) -> R { + super::bufread::reset_encoder_data(&mut self.inner); + self.inner.get_mut().reset(r) + } + + /// Acquires a reference to the underlying reader + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this encoder, returning the underlying reader. + /// + /// Note that there may be buffered bytes which are not re-acquired as part + /// of this transition. It's recommended to only call this function after + /// EOF has been reached. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } + + /// Returns the number of bytes that have been read into this compressor. + /// + /// Note that not all bytes read from the underlying object may be accounted + /// for, there may still be some active buffering. + pub fn total_in(&self) -> u64 { + self.inner.total_in() + } + + /// Returns the number of bytes that the compressor has produced. + /// + /// Note that not all bytes may have been read yet, some may still be + /// buffered. + pub fn total_out(&self) -> u64 { + self.inner.total_out() + } +} + +impl Read for DeflateEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for DeflateEncoder {} + +impl Write for DeflateEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for DeflateEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} + +/// A DEFLATE decoder, or decompressor. +/// +/// This structure implements a [`Read`] interface and takes a stream of +/// compressed data as input, providing the decompressed data when read from. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::DeflateEncoder; +/// use flate2::read::DeflateDecoder; +/// +/// # fn main() { +/// # let mut e = DeflateEncoder::new(Vec::new(), Compression::Default); +/// # e.write(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// // Uncompresses a Deflate Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements Read +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut deflater = DeflateDecoder::new(&bytes[..]); +/// let mut s = String::new(); +/// deflater.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct DeflateDecoder { + inner: bufread::DeflateDecoder>, +} + + + +impl DeflateDecoder { + /// Creates a new decoder which will decompress data read from the given + /// stream. + pub fn new(r: R) -> DeflateDecoder { + DeflateDecoder::new_with_buf(r, vec![0; 32 * 1024]) + } + + /// Same as `new`, but the intermediate buffer for data is specified. + /// + /// Note that the capacity of the intermediate buffer is never increased, + /// and it is recommended for it to be large. + pub fn new_with_buf(r: R, buf: Vec) -> DeflateDecoder { + DeflateDecoder { + inner: bufread::DeflateDecoder::new(BufReader::with_buf(buf, r)), + } + } +} + +impl DeflateDecoder { + /// Resets the state of this decoder entirely, swapping out the input + /// stream for another. + /// + /// This will reset the internal state of this decoder and replace the + /// input stream with the one provided, returning the previous input + /// stream. Future data read from this decoder will be the decompressed + /// version of `r`'s data. + /// + /// Note that there may be currently buffered data when this function is + /// called, and in that case the buffered data is discarded. + pub fn reset(&mut self, r: R) -> R { + super::bufread::reset_decoder_data(&mut self.inner); + self.inner.get_mut().reset(r) + } + + /// Acquires a reference to the underlying stream + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this decoder, returning the underlying reader. + /// + /// Note that there may be buffered bytes which are not re-acquired as part + /// of this transition. It's recommended to only call this function after + /// EOF has been reached. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } + + /// Returns the number of bytes that the decompressor has consumed. + /// + /// Note that this will likely be smaller than what the decompressor + /// actually read from the underlying stream due to buffering. + pub fn total_in(&self) -> u64 { + self.inner.total_in() + } + + /// Returns the number of bytes that the decompressor has produced. + pub fn total_out(&self) -> u64 { + self.inner.total_out() + } +} + +impl Read for DeflateDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + self.inner.read(into) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for DeflateDecoder {} + +impl Write for DeflateDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for DeflateDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} diff --git a/flate2-0.2.20/src/deflate/write.rs b/flate2-0.2.20/src/deflate/write.rs new file mode 100644 index 000000000..596450348 --- /dev/null +++ b/flate2-0.2.20/src/deflate/write.rs @@ -0,0 +1,350 @@ +use std::io::prelude::*; +use std::io; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use zio; +use {Compress, Decompress}; + +/// A DEFLATE encoder, or compressor. +/// +/// This structure implements a [`Write`] interface and takes a stream of +/// uncompressed data, writing the compressed data to the wrapped writer. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use flate2::Compression; +/// use flate2::write::DeflateEncoder; +/// +/// // Vec implements Write to print the compressed bytes of sample string +/// # fn main() { +/// +/// let mut e = DeflateEncoder::new(Vec::new(), Compression::Default); +/// e.write(b"Hello World").unwrap(); +/// println!("{:?}", e.finish().unwrap()); +/// # } +/// ``` +#[derive(Debug)] +pub struct DeflateEncoder { + inner: zio::Writer, +} + +impl DeflateEncoder { + /// Creates a new encoder which will write compressed data to the stream + /// given at the given compression level. + /// + /// When this encoder is dropped or unwrapped the final pieces of data will + /// be flushed. + pub fn new(w: W, level: ::Compression) -> DeflateEncoder { + DeflateEncoder { + inner: zio::Writer::new(w, Compress::new(level, false)), + } + } + + /// Acquires a reference to the underlying writer. + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Acquires a mutable reference to the underlying writer. + /// + /// Note that mutating the output/input state of the stream may corrupt this + /// object, so care must be taken when using this method. + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Resets the state of this encoder entirely, swapping out the output + /// stream for another. + /// + /// This function will finish encoding the current stream into the current + /// output stream before swapping out the two output streams. If the stream + /// cannot be finished an error is returned. + /// + /// After the current stream has been finished, this will reset the internal + /// state of this encoder and replace the output stream with the one + /// provided, returning the previous output stream. Future data written to + /// this encoder will be the compressed into the stream `w` provided. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn reset(&mut self, w: W) -> io::Result { + try!(self.inner.finish()); + self.inner.data.reset(); + Ok(self.inner.replace(w)) + } + + /// Attempt to finish this output stream, writing out final chunks of data. + /// + /// Note that this function can only be used once data has finished being + /// written to the output stream. After this function is called then further + /// calls to `write` may result in a panic. + /// + /// # Panics + /// + /// Attempts to write data to this stream may result in a panic after this + /// function is called. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn try_finish(&mut self) -> io::Result<()> { + self.inner.finish() + } + + /// Consumes this encoder, flushing the output stream. + /// + /// This will flush the underlying data stream, close off the compressed + /// stream and, if successful, return the contained writer. + /// + /// Note that this function may not be suitable to call in a situation where + /// the underlying stream is an asynchronous I/O stream. To finish a stream + /// the `try_finish` (or `shutdown`) method should be used instead. To + /// re-acquire ownership of a stream it is safe to call this method after + /// `try_finish` or `shutdown` has returned `Ok`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn finish(mut self) -> io::Result { + try!(self.inner.finish()); + Ok(self.inner.take_inner()) + } + + /// Consumes this encoder, flushing the output stream. + /// + /// This will flush the underlying data stream and then return the contained + /// writer if the flush succeeded. + /// The compressed stream will not closed but only flushed. This + /// means that obtained byte array can by extended by another deflated + /// stream. To close the stream add the two bytes 0x3 and 0x0. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn flush_finish(mut self) -> io::Result { + try!(self.inner.flush()); + Ok(self.inner.take_inner()) + } + + /// Returns the number of bytes that have been written to this compresor. + /// + /// Note that not all bytes written to this object may be accounted for, + /// there may still be some active buffering. + pub fn total_in(&self) -> u64 { + self.inner.data.total_in() + } + + /// Returns the number of bytes that the compressor has produced. + /// + /// Note that not all bytes may have been written yet, some may still be + /// buffered. + pub fn total_out(&self) -> u64 { + self.inner.data.total_out() + } +} + +impl Write for DeflateEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for DeflateEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + try_nb!(self.inner.finish()); + self.inner.get_mut().shutdown() + } +} + +impl Read for DeflateEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.get_mut().read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for DeflateEncoder {} + +/// A DEFLATE decoder, or decompressor. +/// +/// This structure implements a [`Write`] and will emit a stream of decompressed +/// data when fed a stream of compressed data. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::DeflateEncoder; +/// use flate2::write::DeflateDecoder; +/// +/// # fn main() { +/// # let mut e = DeflateEncoder::new(Vec::new(), Compression::Default); +/// # e.write(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_writer(bytes).unwrap()); +/// # } +/// // Uncompresses a Deflate Encoded vector of bytes and returns a string or error +/// // Here Vec implements Write +/// fn decode_writer(bytes: Vec) -> io::Result { +/// let mut writer = Vec::new(); +/// let mut deflater = DeflateDecoder::new(writer); +/// deflater.write(&bytes[..])?; +/// writer = deflater.finish()?; +/// let return_string = String::from_utf8(writer).expect("String parsing error"); +/// Ok(return_string) +/// } +/// ``` +#[derive(Debug)] +pub struct DeflateDecoder { + inner: zio::Writer, +} + + +impl DeflateDecoder { + /// Creates a new decoder which will write uncompressed data to the stream. + /// + /// When this encoder is dropped or unwrapped the final pieces of data will + /// be flushed. + pub fn new(w: W) -> DeflateDecoder { + DeflateDecoder { + inner: zio::Writer::new(w, Decompress::new(false)), + } + } + + /// Acquires a reference to the underlying writer. + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Acquires a mutable reference to the underlying writer. + /// + /// Note that mutating the output/input state of the stream may corrupt this + /// object, so care must be taken when using this method. + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Resets the state of this decoder entirely, swapping out the output + /// stream for another. + /// + /// This function will finish encoding the current stream into the current + /// output stream before swapping out the two output streams. + /// + /// This will then reset the internal state of this decoder and replace the + /// output stream with the one provided, returning the previous output + /// stream. Future data written to this decoder will be decompressed into + /// the output stream `w`. + /// + /// # Errors + /// + /// This function will perform I/O to finish the stream, and if that I/O + /// returns an error then that will be returned from this function. + pub fn reset(&mut self, w: W) -> io::Result { + try!(self.inner.finish()); + self.inner.data = Decompress::new(false); + Ok(self.inner.replace(w)) + } + + /// Attempt to finish this output stream, writing out final chunks of data. + /// + /// Note that this function can only be used once data has finished being + /// written to the output stream. After this function is called then further + /// calls to `write` may result in a panic. + /// + /// # Panics + /// + /// Attempts to write data to this stream may result in a panic after this + /// function is called. + /// + /// # Errors + /// + /// This function will perform I/O to finish the stream, returning any + /// errors which happen. + pub fn try_finish(&mut self) -> io::Result<()> { + self.inner.finish() + } + + /// Consumes this encoder, flushing the output stream. + /// + /// This will flush the underlying data stream and then return the contained + /// writer if the flush succeeded. + /// + /// Note that this function may not be suitable to call in a situation where + /// the underlying stream is an asynchronous I/O stream. To finish a stream + /// the `try_finish` (or `shutdown`) method should be used instead. To + /// re-acquire ownership of a stream it is safe to call this method after + /// `try_finish` or `shutdown` has returned `Ok`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn finish(mut self) -> io::Result { + try!(self.inner.finish()); + Ok(self.inner.take_inner()) + } + + /// Returns the number of bytes that the decompressor has consumed for + /// decompression. + /// + /// Note that this will likely be smaller than the number of bytes + /// successfully written to this stream due to internal buffering. + pub fn total_in(&self) -> u64 { + self.inner.data.total_in() + } + + /// Returns the number of bytes that the decompressor has written to its + /// output stream. + pub fn total_out(&self) -> u64 { + self.inner.data.total_out() + } +} + +impl Write for DeflateDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for DeflateDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + try_nb!(self.inner.finish()); + self.inner.get_mut().shutdown() + } +} + +impl Read for DeflateDecoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.get_mut().read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for DeflateDecoder {} diff --git a/flate2-0.2.20/src/ffi.rs b/flate2-0.2.20/src/ffi.rs new file mode 100644 index 000000000..92a30a6a7 --- /dev/null +++ b/flate2-0.2.20/src/ffi.rs @@ -0,0 +1,235 @@ +pub use self::imp::*; + +#[cfg(feature = "zlib")] +#[allow(bad_style)] +mod imp { + extern crate libz_sys as z; + use std::mem; + use std::ops::{Deref, DerefMut}; + use libc::{c_int, size_t, c_ulong, c_uint, c_char}; + + pub use self::z::*; + pub use self::z::deflateEnd as mz_deflateEnd; + pub use self::z::inflateEnd as mz_inflateEnd; + pub use self::z::deflateReset as mz_deflateReset; + pub use self::z::deflate as mz_deflate; + pub use self::z::inflate as mz_inflate; + pub use self::z::z_stream as mz_stream; + + pub use self::z::Z_BLOCK as MZ_BLOCK; + pub use self::z::Z_BUF_ERROR as MZ_BUF_ERROR; + pub use self::z::Z_DATA_ERROR as MZ_DATA_ERROR; + pub use self::z::Z_DEFAULT_STRATEGY as MZ_DEFAULT_STRATEGY; + pub use self::z::Z_DEFLATED as MZ_DEFLATED; + pub use self::z::Z_FINISH as MZ_FINISH; + pub use self::z::Z_FULL_FLUSH as MZ_FULL_FLUSH; + pub use self::z::Z_NO_FLUSH as MZ_NO_FLUSH; + pub use self::z::Z_OK as MZ_OK; + pub use self::z::Z_PARTIAL_FLUSH as MZ_PARTIAL_FLUSH; + pub use self::z::Z_STREAM_END as MZ_STREAM_END; + pub use self::z::Z_SYNC_FLUSH as MZ_SYNC_FLUSH; + pub use self::z::Z_STREAM_ERROR as MZ_STREAM_ERROR; + + pub const MZ_DEFAULT_WINDOW_BITS: c_int = 15; + + pub unsafe extern fn mz_crc32(crc: c_ulong, + ptr: *const u8, + len: size_t) -> c_ulong { + z::crc32(crc, ptr, len as c_uint) + } + + pub unsafe extern fn mz_crc32_combine(crc1: c_ulong, + crc2: c_ulong, + len2: z_off_t) -> c_ulong { + z::crc32_combine(crc1, crc2, len2) + } + + const ZLIB_VERSION: &'static str = "1.2.8\0"; + + pub unsafe extern fn mz_deflateInit2(stream: *mut mz_stream, + level: c_int, + method: c_int, + window_bits: c_int, + mem_level: c_int, + strategy: c_int) -> c_int { + z::deflateInit2_(stream, level, method, window_bits, mem_level, + strategy, + ZLIB_VERSION.as_ptr() as *const c_char, + mem::size_of::() as c_int) + } + pub unsafe extern fn mz_inflateInit2(stream: *mut mz_stream, + window_bits: c_int) + -> c_int { + z::inflateInit2_(stream, window_bits, + ZLIB_VERSION.as_ptr() as *const c_char, + mem::size_of::() as c_int) + } + + pub struct StreamWrapper{ + inner: Box, + } + + impl ::std::fmt::Debug for StreamWrapper{ + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error>{ + write!(f, "StreamWrapper") + } + } + + impl Default for StreamWrapper { + fn default() -> StreamWrapper { + StreamWrapper { + inner: Box::new(unsafe{ mem::zeroed() }) + } + } + } + + impl Deref for StreamWrapper { + type Target = mz_stream; + + fn deref(&self) -> &Self::Target { + & *self.inner + } + } + + impl DerefMut for StreamWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.inner + } + } +} + +#[cfg(not(feature = "zlib"))] +mod imp { + extern crate miniz_sys; + use std::mem; + use std::ops::{Deref, DerefMut}; + + use libc::{c_ulong, off_t}; + pub use self::miniz_sys::*; + + pub struct StreamWrapper { + inner: mz_stream, + } + + impl ::std::fmt::Debug for StreamWrapper{ + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error>{ + write!(f, "StreamWrapper") + } + } + + impl Default for StreamWrapper { + fn default() -> StreamWrapper { + StreamWrapper { + inner : unsafe{ mem::zeroed() } + } + } + } + + impl Deref for StreamWrapper { + type Target = mz_stream; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } + + impl DerefMut for StreamWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } + } + + pub unsafe extern fn mz_crc32_combine(crc1: c_ulong, + crc2: c_ulong, + len2: off_t) -> c_ulong { + crc32_combine_(crc1, crc2, len2) + } + + // gf2_matrix_times, gf2_matrix_square and crc32_combine_ are ported from + // zlib. + + fn gf2_matrix_times(mat: &[c_ulong; 32], mut vec: c_ulong) -> c_ulong { + let mut sum = 0; + let mut mat_pos = 0; + while vec != 0 { + if vec & 1 == 1 { + sum ^= mat[mat_pos]; + } + vec >>= 1; + mat_pos += 1; + } + sum + } + + fn gf2_matrix_square(square: &mut [c_ulong; 32], mat: &[c_ulong; 32]) { + for n in 0..32 { + square[n] = gf2_matrix_times(mat, mat[n]); + } + } + + fn crc32_combine_(mut crc1: c_ulong, crc2: c_ulong, mut len2: off_t) -> c_ulong { + let mut row; + + let mut even = [0; 32]; /* even-power-of-two zeros operator */ + let mut odd = [0; 32]; /* odd-power-of-two zeros operator */ + + /* degenerate case (also disallow negative lengths) */ + if len2 <= 0 { + return crc1; + } + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320; /* CRC-32 polynomial */ + row = 1; + for n in 1..32 { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(&mut even, &odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(&mut odd, &even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + loop { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(&mut even, &odd); + if len2 & 1 == 1 { + crc1 = gf2_matrix_times(&even, crc1); + } + len2 >>= 1; + + /* if no more bits set, then done */ + if len2 == 0 { + break; + } + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(&mut odd, &even); + if len2 & 1 == 1 { + crc1 = gf2_matrix_times(&odd, crc1); + } + len2 >>= 1; + + /* if no more bits set, then done */ + if len2 == 0 { + break; + } + } + + /* return combined crc */ + crc1 ^= crc2; + crc1 + } +} + +#[test] +fn crc32_combine() { + let crc32 = unsafe { + imp::mz_crc32_combine(1, 2, 3) + }; + assert_eq!(crc32, 29518389); +} diff --git a/flate2-0.2.20/src/gz/bufread.rs b/flate2-0.2.20/src/gz/bufread.rs new file mode 100644 index 000000000..22be33ae3 --- /dev/null +++ b/flate2-0.2.20/src/gz/bufread.rs @@ -0,0 +1,547 @@ +use std::cmp; +use std::io::prelude::*; +use std::io; +use std::mem; + +use super::{Builder, Header}; +use super::{FCOMMENT, FEXTRA, FHCRC, FNAME}; +use Compression; +use crc::CrcReader; +use deflate; + +fn copy(into: &mut [u8], from: &[u8], pos: &mut usize) -> usize { + let min = cmp::min(into.len(), from.len() - *pos); + for (slot, val) in into.iter_mut().zip(from[*pos..*pos + min].iter()) { + *slot = *val; + } + *pos += min; + return min; +} +fn corrupt() -> io::Error { + io::Error::new( + io::ErrorKind::InvalidInput, + "corrupt gzip stream does not have a matching checksum", + ) +} + +fn bad_header() -> io::Error { + io::Error::new(io::ErrorKind::InvalidInput, "invalid gzip header") +} + +fn read_le_u16(r: &mut R) -> io::Result { + let mut b = [0; 2]; + try!(r.read_exact(&mut b)); + Ok((b[0] as u16) | ((b[1] as u16) << 8)) +} + +fn read_gz_header(r: &mut R) -> io::Result

{ + let mut crc_reader = CrcReader::new(r); + let mut header = [0; 10]; + try!(crc_reader.read_exact(&mut header)); + + let id1 = header[0]; + let id2 = header[1]; + if id1 != 0x1f || id2 != 0x8b { + return Err(bad_header()); + } + let cm = header[2]; + if cm != 8 { + return Err(bad_header()); + } + + let flg = header[3]; + let mtime = ((header[4] as u32) << 0) | ((header[5] as u32) << 8) | ((header[6] as u32) << 16) | + ((header[7] as u32) << 24); + let _xfl = header[8]; + let _os = header[9]; + + let extra = if flg & FEXTRA != 0 { + let xlen = try!(read_le_u16(&mut crc_reader)); + let mut extra = vec![0; xlen as usize]; + try!(crc_reader.read_exact(&mut extra)); + Some(extra) + } else { + None + }; + let filename = if flg & FNAME != 0 { + // wow this is slow + let mut b = Vec::new(); + for byte in crc_reader.by_ref().bytes() { + let byte = try!(byte); + if byte == 0 { + break; + } + b.push(byte); + } + Some(b) + } else { + None + }; + let comment = if flg & FCOMMENT != 0 { + // wow this is slow + let mut b = Vec::new(); + for byte in crc_reader.by_ref().bytes() { + let byte = try!(byte); + if byte == 0 { + break; + } + b.push(byte); + } + Some(b) + } else { + None + }; + + if flg & FHCRC != 0 { + let calced_crc = crc_reader.crc().sum() as u16; + let stored_crc = try!(read_le_u16(&mut crc_reader)); + if calced_crc != stored_crc { + return Err(corrupt()); + } + } + + Ok(Header { + extra: extra, + filename: filename, + comment: comment, + mtime: mtime, + }) +} + + +/// A gzip streaming encoder +/// +/// This structure exposes a [`BufRead`] interface that will read uncompressed data +/// from the underlying reader and expose the compressed version as a [`BufRead`] +/// interface. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// use flate2::Compression; +/// use flate2::bufread::GzEncoder; +/// use std::fs::File; +/// use std::io::BufReader; +/// +/// // Opens sample file, compresses the contents and returns a Vector or error +/// // File wrapped in a BufReader implements BufRead +/// +/// fn open_hello_world() -> io::Result> { +/// let f = File::open("examples/hello_world.txt")?; +/// let b = BufReader::new(f); +/// let mut gz = GzEncoder::new(b, Compression::Fast); +/// let mut buffer = Vec::new(); +/// gz.read_to_end(&mut buffer)?; +/// Ok(buffer) +/// } +/// ``` +#[derive(Debug)] +pub struct GzEncoder { + inner: deflate::bufread::DeflateEncoder>, + header: Vec, + pos: usize, + eof: bool, +} + +pub fn gz_encoder(header: Vec, r: R, lvl: Compression) + -> GzEncoder +{ + let crc = CrcReader::new(r); + GzEncoder { + inner: deflate::bufread::DeflateEncoder::new(crc, lvl), + header: header, + pos: 0, + eof: false, + } +} + +impl GzEncoder { + /// Creates a new encoder which will use the given compression level. + /// + /// The encoder is not configured specially for the emitted header. For + /// header configuration, see the `Builder` type. + /// + /// The data read from the stream `r` will be compressed and available + /// through the returned reader. + pub fn new(r: R, level: Compression) -> GzEncoder { + Builder::new().buf_read(r, level) + } + + fn read_footer(&mut self, into: &mut [u8]) -> io::Result { + if self.pos == 8 { + return Ok(0); + } + let crc = self.inner.get_ref().crc(); + let ref arr = [ + (crc.sum() >> 0) as u8, + (crc.sum() >> 8) as u8, + (crc.sum() >> 16) as u8, + (crc.sum() >> 24) as u8, + (crc.amount() >> 0) as u8, + (crc.amount() >> 8) as u8, + (crc.amount() >> 16) as u8, + (crc.amount() >> 24) as u8, + ]; + Ok(copy(into, arr, &mut self.pos)) + } +} + +impl GzEncoder { + /// Acquires a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying reader. + /// + /// Note that mutation of the reader may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Returns the underlying stream, consuming this encoder + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } +} + +impl Read for GzEncoder { + fn read(&mut self, mut into: &mut [u8]) -> io::Result { + let mut amt = 0; + if self.eof { + return self.read_footer(into); + } else if self.pos < self.header.len() { + amt += copy(into, &self.header, &mut self.pos); + if amt == into.len() { + return Ok(amt); + } + let tmp = into; + into = &mut tmp[amt..]; + } + match try!(self.inner.read(into)) { + 0 => { + self.eof = true; + self.pos = 0; + self.read_footer(into) + } + n => Ok(amt + n), + } + } +} + +impl Write for GzEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + + +/// A gzip streaming decoder +/// +/// This structure exposes a [`ReadBuf`] interface that will consume compressed +/// data from the underlying reader and emit uncompressed data. +/// +/// [`ReadBuf`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::GzEncoder; +/// use flate2::bufread::GzDecoder; +/// +/// # fn main() { +/// # let mut e = GzEncoder::new(Vec::new(), Compression::Default); +/// # e.write(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Gz Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements BufRead +/// +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut gz = GzDecoder::new(&bytes[..])?; +/// let mut s = String::new(); +/// gz.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct GzDecoder { + inner: CrcReader>, + header: Header, + finished: bool, +} + + +impl GzDecoder { + /// Creates a new decoder from the given reader, immediately parsing the + /// gzip header. + /// + /// # Errors + /// + /// If an error is encountered when parsing the gzip header, an error is + /// returned. + pub fn new(mut r: R) -> io::Result> { + let header = try!(read_gz_header(&mut r)); + + let flate = deflate::bufread::DeflateDecoder::new(r); + return Ok(GzDecoder { + inner: CrcReader::new(flate), + header: header, + finished: false, + }); + } + + fn finish(&mut self) -> io::Result<()> { + if self.finished { + return Ok(()); + } + let ref mut buf = [0u8; 8]; + { + let mut len = 0; + + while len < buf.len() { + match try!(self.inner.get_mut().get_mut().read(&mut buf[len..])) { + 0 => return Err(corrupt()), + n => len += n, + } + } + } + + let crc = ((buf[0] as u32) << 0) | ((buf[1] as u32) << 8) | ((buf[2] as u32) << 16) | + ((buf[3] as u32) << 24); + let amt = ((buf[4] as u32) << 0) | ((buf[5] as u32) << 8) | ((buf[6] as u32) << 16) | + ((buf[7] as u32) << 24); + if crc != self.inner.crc().sum() as u32 { + return Err(corrupt()); + } + if amt != self.inner.crc().amount() { + return Err(corrupt()); + } + self.finished = true; + Ok(()) + } +} + +impl GzDecoder { + /// Returns the header associated with this stream. + pub fn header(&self) -> &Header { + &self.header + } + + /// Acquires a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream. + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this decoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } +} + +impl Read for GzDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + match try!(self.inner.read(into)) { + 0 => { + try!(self.finish()); + Ok(0) + } + n => Ok(n), + } + } +} + +impl Write for GzDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + + + +/// A gzip streaming decoder that decodes all members of a multistream +/// +/// A gzip member consists of a header, compressed data and a trailer. The [gzip +/// specification](https://tools.ietf.org/html/rfc1952), however, allows multiple +/// gzip members to be joined in a single stream. `MultiGzDecoder` will +/// decode all consecutive members while `GzDecoder` will only decompress +/// the first gzip member. The multistream format is commonly used in +/// bioinformatics, for example when using the BGZF compressed data. +/// +/// This structure exposes a [`BufRead`] interface that will consume all gzip members +/// from the underlying reader and emit uncompressed data. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::GzEncoder; +/// use flate2::bufread::MultiGzDecoder; +/// +/// # fn main() { +/// # let mut e = GzEncoder::new(Vec::new(), Compression::Default); +/// # e.write(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Gz Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements BufRead +/// +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut gz = MultiGzDecoder::new(&bytes[..])?; +/// let mut s = String::new(); +/// gz.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct MultiGzDecoder { + inner: CrcReader>, + header: Header, + finished: bool, +} + + +impl MultiGzDecoder { + /// Creates a new decoder from the given reader, immediately parsing the + /// (first) gzip header. If the gzip stream contains multiple members all will + /// be decoded. + /// + /// # Errors + /// + /// If an error is encountered when parsing the gzip header, an error is + /// returned. + pub fn new(mut r: R) -> io::Result> { + let header = try!(read_gz_header(&mut r)); + + let flate = deflate::bufread::DeflateDecoder::new(r); + return Ok(MultiGzDecoder { + inner: CrcReader::new(flate), + header: header, + finished: false, + }); + } + + fn finish_member(&mut self) -> io::Result { + if self.finished { + return Ok(0); + } + let ref mut buf = [0u8; 8]; + { + let mut len = 0; + + while len < buf.len() { + match try!(self.inner.get_mut().get_mut().read(&mut buf[len..])) { + 0 => return Err(corrupt()), + n => len += n, + } + } + } + + let crc = ((buf[0] as u32) << 0) | ((buf[1] as u32) << 8) | ((buf[2] as u32) << 16) | + ((buf[3] as u32) << 24); + let amt = ((buf[4] as u32) << 0) | ((buf[5] as u32) << 8) | ((buf[6] as u32) << 16) | + ((buf[7] as u32) << 24); + if crc != self.inner.crc().sum() as u32 { + return Err(corrupt()); + } + if amt != self.inner.crc().amount() { + return Err(corrupt()); + } + let remaining = match self.inner.get_mut().get_mut().fill_buf() { + Ok(b) => if b.is_empty() { + self.finished = true; + return Ok(0); + } else { + b.len() + }, + Err(e) => return Err(e), + }; + + let next_header = try!(read_gz_header(self.inner.get_mut().get_mut())); + mem::replace(&mut self.header, next_header); + self.inner.reset(); + self.inner.get_mut().reset_data(); + + Ok(remaining) + } +} + +impl MultiGzDecoder { + /// Returns the current header associated with this stream. + pub fn header(&self) -> &Header { + &self.header + } + + /// Acquires a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream. + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this decoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } +} + +impl Read for MultiGzDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + match try!(self.inner.read(into)) { + 0 => match self.finish_member() { + Ok(0) => Ok(0), + Ok(_) => self.read(into), + Err(e) => Err(e), + }, + n => Ok(n), + } + } +} + +impl Write for MultiGzDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} diff --git a/flate2-0.2.20/src/gz/mod.rs b/flate2-0.2.20/src/gz/mod.rs new file mode 100644 index 000000000..04ff5fcf0 --- /dev/null +++ b/flate2-0.2.20/src/gz/mod.rs @@ -0,0 +1,344 @@ +use std::env; +use std::ffi::CString; +use std::io::prelude::*; +use std::time; + +use Compression; +use bufreader::BufReader; + +pub static FHCRC: u8 = 1 << 1; +pub static FEXTRA: u8 = 1 << 2; +pub static FNAME: u8 = 1 << 3; +pub static FCOMMENT: u8 = 1 << 4; + +pub mod bufread; +pub mod read; +pub mod write; + + +/// A structure representing the header of a gzip stream. +/// +/// The header can contain metadata about the file that was compressed, if +/// present. +#[derive(PartialEq, Debug)] +pub struct Header { + extra: Option>, + filename: Option>, + comment: Option>, + mtime: u32, +} + +impl Header { + /// Returns the `filename` field of this gzip stream's header, if present. + pub fn filename(&self) -> Option<&[u8]> { + self.filename.as_ref().map(|s| &s[..]) + } + + /// Returns the `extra` field of this gzip stream's header, if present. + pub fn extra(&self) -> Option<&[u8]> { + self.extra.as_ref().map(|s| &s[..]) + } + + /// Returns the `comment` field of this gzip stream's header, if present. + pub fn comment(&self) -> Option<&[u8]> { + self.comment.as_ref().map(|s| &s[..]) + } + + /// This gives the most recent modification time of the original file being compressed. + /// + /// The time is in Unix format, i.e., seconds since 00:00:00 GMT, Jan. 1, 1970. + /// (Note that this may cause problems for MS-DOS and other systems that use local + /// rather than Universal time.) If the compressed data did not come from a file, + /// `mtime` is set to the time at which compression started. + /// `mtime` = 0 means no time stamp is available. + /// + /// The usage of `mtime` is discouraged because of Year 2038 problem. + pub fn mtime(&self) -> u32 { + self.mtime + } + + /// Returns the most recent modification time represented by a date-time type. + /// Returns `None` if the value of the underlying counter is 0, + /// indicating no time stamp is available. + /// + /// + /// The time is measured as seconds since 00:00:00 GMT, Jan. 1 1970. + /// See [`mtime`](#method.mtime) for more detail. + pub fn mtime_as_datetime(&self) -> Option { + if self.mtime == 0 { + None + } else { + let duration = time::Duration::new(u64::from(self.mtime), 0); + let datetime = time::UNIX_EPOCH + duration; + Some(datetime) + } + } +} + +/// A builder structure to create a new gzip Encoder. +/// +/// This structure controls header configuration options such as the filename. +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// # use std::io; +/// use std::fs::File; +/// use flate2::GzBuilder; +/// use flate2::Compression; +/// +/// // GzBuilder opens a file and writes a sample string using Builder pattern +/// +/// # fn sample_builder() -> Result<(), io::Error> { +/// let f = File::create("examples/hello_world.gz")?; +/// let mut gz = GzBuilder::new() +/// .filename("hello_world.txt") +/// .comment("test file, please delete") +/// .write(f, Compression::Default); +/// gz.write(b"hello world")?; +/// gz.finish()?; +/// # Ok(()) +/// # } +/// ``` +#[derive(Debug)] +pub struct Builder { + extra: Option>, + filename: Option, + comment: Option, + mtime: u32, +} + +impl Builder { + /// Create a new blank builder with no header by default. + pub fn new() -> Builder { + Builder { + extra: None, + filename: None, + comment: None, + mtime: 0, + } + } + + /// Configure the `mtime` field in the gzip header. + pub fn mtime(mut self, mtime: u32) -> Builder { + self.mtime = mtime; + self + } + + /// Configure the `extra` field in the gzip header. + pub fn extra>>(mut self, extra: T) -> Builder { + self.extra = Some(extra.into()); + self + } + + /// Configure the `filename` field in the gzip header. + /// + /// # Panics + /// + /// Panics if the `filename` slice contains a zero. + pub fn filename>>(mut self, filename: T) -> Builder { + self.filename = Some(CString::new(filename.into()).unwrap()); + self + } + + /// Configure the `comment` field in the gzip header. + /// + /// # Panics + /// + /// Panics if the `comment` slice contains a zero. + pub fn comment>>(mut self, comment: T) -> Builder { + self.comment = Some(CString::new(comment.into()).unwrap()); + self + } + + /// Consume this builder, creating a writer encoder in the process. + /// + /// The data written to the returned encoder will be compressed and then + /// written out to the supplied parameter `w`. + pub fn write(self, w: W, lvl: Compression) -> write::GzEncoder { + write::gz_encoder(self.into_header(lvl), w, lvl) + } + + /// Consume this builder, creating a reader encoder in the process. + /// + /// Data read from the returned encoder will be the compressed version of + /// the data read from the given reader. + pub fn read(self, r: R, lvl: Compression) -> read::GzEncoder { + read::gz_encoder(self.buf_read(BufReader::new(r), lvl)) + } + + /// Consume this builder, creating a reader encoder in the process. + /// + /// Data read from the returned encoder will be the compressed version of + /// the data read from the given reader. + pub fn buf_read(self, r: R, lvl: Compression) -> bufread::GzEncoder + where + R: BufRead, + { + bufread::gz_encoder(self.into_header(lvl), r, lvl) + } + + fn into_header(self, lvl: Compression) -> Vec { + let Builder { + extra, + filename, + comment, + mtime, + } = self; + let mut flg = 0; + let mut header = vec![0u8; 10]; + match extra { + Some(v) => { + flg |= FEXTRA; + header.push((v.len() >> 0) as u8); + header.push((v.len() >> 8) as u8); + header.extend(v); + } + None => {} + } + match filename { + Some(filename) => { + flg |= FNAME; + header.extend(filename.as_bytes_with_nul().iter().map(|x| *x)); + } + None => {} + } + match comment { + Some(comment) => { + flg |= FCOMMENT; + header.extend(comment.as_bytes_with_nul().iter().map(|x| *x)); + } + None => {} + } + header[0] = 0x1f; + header[1] = 0x8b; + header[2] = 8; + header[3] = flg; + header[4] = (mtime >> 0) as u8; + header[5] = (mtime >> 8) as u8; + header[6] = (mtime >> 16) as u8; + header[7] = (mtime >> 24) as u8; + header[8] = match lvl { + Compression::Best => 2, + Compression::Fast => 4, + _ => 0, + }; + + // Typically this byte indicates what OS the gz stream was created on, + // but in an effort to have cross-platform reproducible streams just + // always set this to 255. I'm not sure that if we "correctly" set this + // it'd do anything anyway... + header[9] = 255; + return header; + } +} + +#[cfg(test)] +mod tests { + use std::io::prelude::*; + + use super::{read, write, Builder}; + use Compression::Default; + use rand::{thread_rng, Rng}; + + #[test] + fn roundtrip() { + let mut e = write::GzEncoder::new(Vec::new(), Default); + e.write_all(b"foo bar baz").unwrap(); + let inner = e.finish().unwrap(); + let mut d = read::GzDecoder::new(&inner[..]).unwrap(); + let mut s = String::new(); + d.read_to_string(&mut s).unwrap(); + assert_eq!(s, "foo bar baz"); + } + + #[test] + fn roundtrip_zero() { + let e = write::GzEncoder::new(Vec::new(), Default); + let inner = e.finish().unwrap(); + let mut d = read::GzDecoder::new(&inner[..]).unwrap(); + let mut s = String::new(); + d.read_to_string(&mut s).unwrap(); + assert_eq!(s, ""); + } + + #[test] + fn roundtrip_big() { + let mut real = Vec::new(); + let mut w = write::GzEncoder::new(Vec::new(), Default); + let v = thread_rng().gen_iter::().take(1024).collect::>(); + for _ in 0..200 { + let to_write = &v[..thread_rng().gen_range(0, v.len())]; + real.extend(to_write.iter().map(|x| *x)); + w.write_all(to_write).unwrap(); + } + let result = w.finish().unwrap(); + let mut r = read::GzDecoder::new(&result[..]).unwrap(); + let mut v = Vec::new(); + r.read_to_end(&mut v).unwrap(); + assert!(v == real); + } + + #[test] + fn roundtrip_big2() { + let v = thread_rng() + .gen_iter::() + .take(1024 * 1024) + .collect::>(); + let mut r = read::GzDecoder::new(read::GzEncoder::new(&v[..], Default)).unwrap(); + let mut res = Vec::new(); + r.read_to_end(&mut res).unwrap(); + assert!(res == v); + } + + #[test] + fn fields() { + let r = vec![0, 2, 4, 6]; + let e = Builder::new() + .filename("foo.rs") + .comment("bar") + .extra(vec![0, 1, 2, 3]) + .read(&r[..], Default); + let mut d = read::GzDecoder::new(e).unwrap(); + assert_eq!(d.header().filename(), Some(&b"foo.rs"[..])); + assert_eq!(d.header().comment(), Some(&b"bar"[..])); + assert_eq!(d.header().extra(), Some(&b"\x00\x01\x02\x03"[..])); + let mut res = Vec::new(); + d.read_to_end(&mut res).unwrap(); + assert_eq!(res, vec![0, 2, 4, 6]); + } + + #[test] + fn keep_reading_after_end() { + let mut e = write::GzEncoder::new(Vec::new(), Default); + e.write_all(b"foo bar baz").unwrap(); + let inner = e.finish().unwrap(); + let mut d = read::GzDecoder::new(&inner[..]).unwrap(); + let mut s = String::new(); + d.read_to_string(&mut s).unwrap(); + assert_eq!(s, "foo bar baz"); + d.read_to_string(&mut s).unwrap(); + assert_eq!(s, "foo bar baz"); + } + + #[test] + fn qc_reader() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(v: Vec) -> bool { + let r = read::GzEncoder::new(&v[..], Default); + let mut r = read::GzDecoder::new(r).unwrap(); + let mut v2 = Vec::new(); + r.read_to_end(&mut v2).unwrap(); + v == v2 + } + } + + #[test] + fn flush_after_write() { + let mut f = write::GzEncoder::new(Vec::new(), Default); + write!(f, "Hello world").unwrap(); + f.flush().unwrap(); + } +} diff --git a/flate2-0.2.20/src/gz/read.rs b/flate2-0.2.20/src/gz/read.rs new file mode 100644 index 000000000..c95e388a5 --- /dev/null +++ b/flate2-0.2.20/src/gz/read.rs @@ -0,0 +1,286 @@ +use std::io::prelude::*; +use std::io; + +use super::{Builder, Header}; +use Compression; +use bufreader::BufReader; +use super::bufread; + +/// A gzip streaming encoder +/// +/// This structure exposes a [`Read`] interface that will read uncompressed data +/// from the underlying reader and expose the compressed version as a [`Read`] +/// interface. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// use flate2::Compression; +/// use flate2::read::GzEncoder; +/// +/// // Return a vector containing the GZ compressed version of hello world +/// +/// fn gzencode_hello_world() -> io::Result> { +/// let mut ret_vec = [0;100]; +/// let bytestring = b"hello world"; +/// let mut gz = GzEncoder::new(&bytestring[..], Compression::Fast); +/// let count = gz.read(&mut ret_vec)?; +/// Ok(ret_vec[0..count].to_vec()) +/// } +/// ``` +#[derive(Debug)] +pub struct GzEncoder { + inner: bufread::GzEncoder>, +} + +pub fn gz_encoder(inner: bufread::GzEncoder>) + -> GzEncoder +{ + GzEncoder { inner: inner } +} + +impl GzEncoder { + /// Creates a new encoder which will use the given compression level. + /// + /// The encoder is not configured specially for the emitted header. For + /// header configuration, see the `Builder` type. + /// + /// The data read from the stream `r` will be compressed and available + /// through the returned reader. + pub fn new(r: R, level: Compression) -> GzEncoder { + Builder::new().read(r, level) + } +} + +impl GzEncoder { + /// Acquires a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying reader. + /// + /// Note that mutation of the reader may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Returns the underlying stream, consuming this encoder + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } +} + +impl Read for GzEncoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + self.inner.read(into) + } +} + +impl Write for GzEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +/// A gzip streaming decoder +/// +/// This structure exposes a [`Read`] interface that will consume compressed +/// data from the underlying reader and emit uncompressed data. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::GzEncoder; +/// use flate2::read::GzDecoder; +/// +/// # fn main() { +/// # let mut e = GzEncoder::new(Vec::new(), Compression::Default); +/// # e.write(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Gz Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements Read +/// +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut gz = GzDecoder::new(&bytes[..])?; +/// let mut s = String::new(); +/// gz.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct GzDecoder { + inner: bufread::GzDecoder>, +} + +impl GzDecoder { + /// Creates a new decoder from the given reader, immediately parsing the + /// gzip header. + /// + /// # Errors + /// + /// If an error is encountered when parsing the gzip header, an error is + /// returned. + pub fn new(r: R) -> io::Result> { + bufread::GzDecoder::new(BufReader::new(r)).map(|r| GzDecoder { inner: r }) + } +} + +impl GzDecoder { + /// Returns the header associated with this stream. + pub fn header(&self) -> &Header { + self.inner.header() + } + + /// Acquires a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream. + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this decoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } +} + +impl Read for GzDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + self.inner.read(into) + } +} + +impl Write for GzDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +/// A gzip streaming decoder that decodes all members of a multistream +/// +/// A gzip member consists of a header, compressed data and a trailer. The [gzip +/// specification](https://tools.ietf.org/html/rfc1952), however, allows multiple +/// gzip members to be joined in a single stream. `MultiGzDecoder` will +/// decode all consecutive members while `GzDecoder` will only decompress the +/// first gzip member. The multistream format is commonly used in bioinformatics, +/// for example when using the BGZF compressed data. +/// +/// This structure exposes a [`Read`] interface that will consume all gzip members +/// from the underlying reader and emit uncompressed data. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::GzEncoder; +/// use flate2::read::MultiGzDecoder; +/// +/// # fn main() { +/// # let mut e = GzEncoder::new(Vec::new(), Compression::Default); +/// # e.write(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Gz Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements Read +/// +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut gz = MultiGzDecoder::new(&bytes[..])?; +/// let mut s = String::new(); +/// gz.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct MultiGzDecoder { + inner: bufread::MultiGzDecoder>, +} + +impl MultiGzDecoder { + /// Creates a new decoder from the given reader, immediately parsing the + /// (first) gzip header. If the gzip stream contains multiple members all will + /// be decoded. + /// + /// # Errors + /// + /// If an error is encountered when parsing the gzip header, an error is + /// returned. + pub fn new(r: R) -> io::Result> { + bufread::MultiGzDecoder::new(BufReader::new(r)).map(|r| MultiGzDecoder { inner: r }) + } +} + +impl MultiGzDecoder { + /// Returns the current header associated with this stream. + pub fn header(&self) -> &Header { + self.inner.header() + } + + /// Acquires a reference to the underlying reader. + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream. + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this decoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } +} + +impl Read for MultiGzDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + self.inner.read(into) + } +} + +impl Write for MultiGzDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} diff --git a/flate2-0.2.20/src/gz/write.rs b/flate2-0.2.20/src/gz/write.rs new file mode 100644 index 000000000..a9a10569a --- /dev/null +++ b/flate2-0.2.20/src/gz/write.rs @@ -0,0 +1,182 @@ +use std::io::prelude::*; +use std::io; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use super::Builder; +use {Compress, Compression}; +use crc::Crc; +use zio; + +/// A gzip streaming encoder +/// +/// This structure exposes a [`Write`] interface that will emit compressed data +/// to the underlying writer `W`. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use flate2::Compression; +/// use flate2::write::GzEncoder; +/// +/// // Vec implements Write to print the compressed bytes of sample string +/// # fn main() { +/// +/// let mut e = GzEncoder::new(Vec::new(), Compression::Default); +/// e.write(b"Hello World").unwrap(); +/// println!("{:?}", e.finish().unwrap()); +/// # } +/// ``` +#[derive(Debug)] +pub struct GzEncoder { + inner: zio::Writer, + crc: Crc, + crc_bytes_written: usize, + header: Vec, +} + +pub fn gz_encoder(header: Vec, w: W, lvl: Compression) -> GzEncoder { + GzEncoder { + inner: zio::Writer::new(w, Compress::new(lvl, false)), + crc: Crc::new(), + header: header, + crc_bytes_written: 0, + } +} + +impl GzEncoder { + /// Creates a new encoder which will use the given compression level. + /// + /// The encoder is not configured specially for the emitted header. For + /// header configuration, see the `Builder` type. + /// + /// The data written to the returned encoder will be compressed and then + /// written to the stream `w`. + pub fn new(w: W, level: Compression) -> GzEncoder { + Builder::new().write(w, level) + } + + /// Acquires a reference to the underlying writer. + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Acquires a mutable reference to the underlying writer. + /// + /// Note that mutation of the writer may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Attempt to finish this output stream, writing out final chunks of data. + /// + /// Note that this function can only be used once data has finished being + /// written to the output stream. After this function is called then further + /// calls to `write` may result in a panic. + /// + /// # Panics + /// + /// Attempts to write data to this stream may result in a panic after this + /// function is called. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn try_finish(&mut self) -> io::Result<()> { + try!(self.write_header()); + try!(self.inner.finish()); + + while self.crc_bytes_written < 8 { + let (sum, amt) = (self.crc.sum() as u32, self.crc.amount()); + let buf = [ + (sum >> 0) as u8, + (sum >> 8) as u8, + (sum >> 16) as u8, + (sum >> 24) as u8, + (amt >> 0) as u8, + (amt >> 8) as u8, + (amt >> 16) as u8, + (amt >> 24) as u8, + ]; + let inner = self.inner.get_mut(); + let n = try!(inner.write(&buf[self.crc_bytes_written..])); + self.crc_bytes_written += n; + } + Ok(()) + } + + /// Finish encoding this stream, returning the underlying writer once the + /// encoding is done. + /// + /// Note that this function may not be suitable to call in a situation where + /// the underlying stream is an asynchronous I/O stream. To finish a stream + /// the `try_finish` (or `shutdown`) method should be used instead. To + /// re-acquire ownership of a stream it is safe to call this method after + /// `try_finish` or `shutdown` has returned `Ok`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn finish(mut self) -> io::Result { + try!(self.try_finish()); + Ok(self.inner.take_inner()) + } + + fn write_header(&mut self) -> io::Result<()> { + while self.header.len() > 0 { + let n = try!(self.inner.get_mut().write(&self.header)); + self.header.drain(..n); + } + Ok(()) + } +} + +impl Write for GzEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + assert_eq!(self.crc_bytes_written, 0); + try!(self.write_header()); + let n = try!(self.inner.write(buf)); + self.crc.update(&buf[..n]); + Ok(n) + } + + fn flush(&mut self) -> io::Result<()> { + assert_eq!(self.crc_bytes_written, 0); + try!(self.write_header()); + self.inner.flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for GzEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + try_nb!(self.try_finish()); + self.get_mut().shutdown() + } +} + +impl Read for GzEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.get_mut().read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for GzEncoder {} + +impl Drop for GzEncoder { + fn drop(&mut self) { + if self.inner.is_present() { + let _ = self.try_finish(); + } + } +} diff --git a/flate2-0.2.20/src/lib.rs b/flate2-0.2.20/src/lib.rs new file mode 100644 index 000000000..3846913b9 --- /dev/null +++ b/flate2-0.2.20/src/lib.rs @@ -0,0 +1,308 @@ +//! A DEFLATE-based stream compression/decompression library +//! +//! This library is meant to supplement/replace the standard distributon's +//! libflate library by providing a streaming encoder/decoder rather than purely +//! an in-memory encoder/decoder. +//! +//! Like with [`libflate`], flate2 is based on [`miniz.c`][1] +//! +//! [1]: https://code.google.com/p/miniz/ +//! [`libflate`]: https://docs.rs/crate/libflate/ +//! +//! # Organization +//! +//! This crate consists mainly of two modules, [`read`] and [`write`]. Each +//! module contains a number of types used to encode and decode various streams +//! of data. All types in the [`write`] module work on instances of [`Write`], +//! whereas all types in the [`read`] module work on instances of [`Read`]. +//! +//! ``` +//! use flate2::write::GzEncoder; +//! use flate2::Compression; +//! use std::io; +//! use std::io::prelude::*; +//! +//! # fn main() { let _ = run(); } +//! # fn run() -> io::Result<()> { +//! let mut encoder = GzEncoder::new(Vec::new(), Compression::Default); +//! encoder.write(b"Example")?; +//! # Ok(()) +//! # } +//! ``` +//! +//! +//! Other various types are provided at the top-level of the crate for +//! management and dealing with encoders/decoders. +//! +//! [`read`]: read/index.html +//! [`write`]: write/index.html +//! [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +//! [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +//! +//! # Helper traits +//! +//! There are two helper traits provided: [`FlateReadExt`] and [`FlateWriteExt`]. +//! These provide convenience methods for creating a decoder/encoder out of an +//! already existing stream to chain construction. +//! +//! [`FlateReadExt`]: trait.FlateReadExt.html +//! [`FlateWriteExt`]: trait.FlateWriteExt.html +//! +//! ``` +//! use flate2::{FlateReadExt, Compression}; +//! use std::io::prelude::*; +//! use std::io; +//! use std::fs::File; +//! +//! # fn main() { +//! # println!("{}", run().unwrap()); +//! # } +//! # +//! // Read contents of file with a compression stream, then decompress with GZ +//! +//! # fn run() -> io::Result { +//! let f = File::open("examples/hello_world.txt")?; +//! +//! //gz_encode method comes from FlateReadExt and applies to a std::fs::File +//! let data = f.gz_encode(Compression::Default); +//! let mut buffer = String::new(); +//! +//! //gz_decode method comes from FlateReadExt and applies to a &[u8] +//! &data.gz_decode()?.read_to_string(&mut buffer)?; +//! # Ok(buffer) +//! # } +//! ``` +//! +//! # Async I/O +//! +//! This crate optionally can support async I/O streams with the [Tokio stack] via +//! the `tokio` feature of this crate: +//! +//! [Tokio stack]: https://tokio.rs/ +//! +//! ```toml +//! flate2 = { version = "0.2", features = ["tokio"] } +//! ``` +//! +//! All methods are internally capable of working with streams that may return +//! [`ErrorKind::WouldBlock`] when they're not ready to perform the particular +//! operation. +//! +//! [`ErrorKind::WouldBlock`]: https://doc.rust-lang.org/std/io/enum.ErrorKind.html +//! +//! Note that care needs to be taken when using these objects, however. The +//! Tokio runtime, in particular, requires that data is fully flushed before +//! dropping streams. For compatibility with blocking streams all streams are +//! flushed/written when they are dropped, and this is not always a suitable +//! time to perform I/O. If I/O streams are flushed before drop, however, then +//! these operations will be a noop. +#![doc(html_root_url = "https://docs.rs/flate2/0.2")] +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![allow(trivial_numeric_casts)] +#![cfg_attr(test, deny(warnings))] + +#[cfg(feature = "tokio")] +extern crate futures; +extern crate libc; +#[cfg(test)] +extern crate quickcheck; +#[cfg(test)] +extern crate rand; +#[cfg(feature = "tokio")] +#[macro_use] +extern crate tokio_io; + +use std::io::prelude::*; +use std::io; + +pub use gz::Builder as GzBuilder; +pub use gz::Header as GzHeader; +pub use mem::{Compress, DataError, Decompress, Flush, Status}; +pub use crc::{Crc, CrcReader}; + +mod bufreader; +mod crc; +mod deflate; +mod ffi; +mod gz; +mod zio; +mod mem; +mod zlib; + +/// Types which operate over [`Read`] streams, both encoders and decoders for +/// various formats. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +pub mod read { + pub use deflate::read::DeflateEncoder; + pub use deflate::read::DeflateDecoder; + pub use zlib::read::ZlibEncoder; + pub use zlib::read::ZlibDecoder; + pub use gz::read::GzEncoder; + pub use gz::read::GzDecoder; + pub use gz::read::MultiGzDecoder; +} + +/// Types which operate over [`Write`] streams, both encoders and decoders for +/// various formats. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +pub mod write { + pub use deflate::write::DeflateEncoder; + pub use deflate::write::DeflateDecoder; + pub use zlib::write::ZlibEncoder; + pub use zlib::write::ZlibDecoder; + pub use gz::write::GzEncoder; +} + +/// Types which operate over [`BufRead`] streams, both encoders and decoders for +/// various formats. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +pub mod bufread { + pub use deflate::bufread::DeflateEncoder; + pub use deflate::bufread::DeflateDecoder; + pub use zlib::bufread::ZlibEncoder; + pub use zlib::bufread::ZlibDecoder; + pub use gz::bufread::GzEncoder; + pub use gz::bufread::GzDecoder; + pub use gz::bufread::MultiGzDecoder; +} + +fn _assert_send_sync() { + fn _assert_send_sync() {} + + _assert_send_sync::>(); + _assert_send_sync::>(); + _assert_send_sync::>(); + _assert_send_sync::>(); + _assert_send_sync::>(); + _assert_send_sync::>(); + _assert_send_sync::>(); + _assert_send_sync::>>(); + _assert_send_sync::>>(); + _assert_send_sync::>>(); + _assert_send_sync::>>(); + _assert_send_sync::>>(); +} + +/// When compressing data, the compression level can be specified by a value in +/// this enum. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Compression { + /// No compression is to be performed, this may actually inflate data + /// slightly when encoding. + None = 0, + /// Optimize for the best speed of encoding. + Fast = 1, + /// Optimize for the size of data being encoded. + Best = 9, + /// Choose the default compression, a balance between speed and size. + Default = 6, +} + +/// Default to Compression::Default. +impl Default for Compression { + fn default() -> Compression { + Compression::Default + } +} + +/// A helper trait to create encoder/decoders with method syntax. +pub trait FlateReadExt: Read + Sized { + /// Consume this reader to create a compression stream at the specified + /// compression level. + fn gz_encode(self, lvl: Compression) -> read::GzEncoder { + read::GzEncoder::new(self, lvl) + } + + /// Consume this reader to create a decompression stream of this stream. + fn gz_decode(self) -> io::Result> { + read::GzDecoder::new(self) + } + + /// Consume this reader to create a compression stream at the specified + /// compression level. + fn zlib_encode(self, lvl: Compression) -> read::ZlibEncoder { + read::ZlibEncoder::new(self, lvl) + } + + /// Consume this reader to create a decompression stream of this stream. + fn zlib_decode(self) -> read::ZlibDecoder { + read::ZlibDecoder::new(self) + } + + /// Consume this reader to create a compression stream at the specified + /// compression level. + fn deflate_encode(self, lvl: Compression) -> read::DeflateEncoder { + read::DeflateEncoder::new(self, lvl) + } + + /// Consume this reader to create a decompression stream of this stream. + fn deflate_decode(self) -> read::DeflateDecoder { + read::DeflateDecoder::new(self) + } +} + +/// A helper trait to create encoder/decoders with method syntax. +pub trait FlateWriteExt: Write + Sized { + /// Consume this writer to create a compression stream at the specified + /// compression level. + fn gz_encode(self, lvl: Compression) -> write::GzEncoder { + write::GzEncoder::new(self, lvl) + } + + // TODO: coming soon to a theater near you! + // /// Consume this writer to create a decompression stream of this stream. + // fn gz_decode(self) -> IoResult> { + // write::GzDecoder::new(self) + // } + + /// Consume this writer to create a compression stream at the specified + /// compression level. + fn zlib_encode(self, lvl: Compression) -> write::ZlibEncoder { + write::ZlibEncoder::new(self, lvl) + } + + /// Consume this writer to create a decompression stream of this stream. + fn zlib_decode(self) -> write::ZlibDecoder { + write::ZlibDecoder::new(self) + } + + /// Consume this writer to create a compression stream at the specified + /// compression level. + fn deflate_encode(self, lvl: Compression) -> write::DeflateEncoder { + write::DeflateEncoder::new(self, lvl) + } + + /// Consume this writer to create a decompression stream of this stream. + fn deflate_decode(self) -> write::DeflateDecoder { + write::DeflateDecoder::new(self) + } +} + +impl FlateReadExt for T {} +impl FlateWriteExt for T {} + +#[cfg(test)] +mod test { + use std::io::prelude::*; + use {Compression, FlateReadExt}; + + #[test] + fn crazy() { + let rdr = &mut b"foobar"; + let mut res = Vec::new(); + rdr.gz_encode(Compression::Default) + .deflate_encode(Compression::Default) + .zlib_encode(Compression::Default) + .zlib_decode() + .deflate_decode() + .gz_decode() + .unwrap() + .read_to_end(&mut res) + .unwrap(); + assert_eq!(res, b"foobar"); + } +} diff --git a/flate2-0.2.20/src/mem.rs b/flate2-0.2.20/src/mem.rs new file mode 100644 index 000000000..3eaf36abe --- /dev/null +++ b/flate2-0.2.20/src/mem.rs @@ -0,0 +1,516 @@ +use std::error::Error; +use std::fmt; +use std::io; +use std::marker; +use std::slice; + +use libc::{c_int, c_uint}; + +use Compression; +use ffi; + +/// Raw in-memory compression stream for blocks of data. +/// +/// This type is the building block for the I/O streams in the rest of this +/// crate. It requires more management than the [`Read`]/[`Write`] API but is +/// maximally flexible in terms of accepting input from any source and being +/// able to produce output to any memory location. +/// +/// It is recommended to use the I/O stream adaptors over this type as they're +/// easier to use. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +#[derive(Debug)] +pub struct Compress { + inner: Stream, +} + +/// Raw in-memory decompression stream for blocks of data. +/// +/// This type is the building block for the I/O streams in the rest of this +/// crate. It requires more management than the [`Read`]/[`Write`] API but is +/// maximally flexible in terms of accepting input from any source and being +/// able to produce output to any memory location. +/// +/// It is recommended to use the I/O stream adaptors over this type as they're +/// easier to use. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +#[derive(Debug)] +pub struct Decompress { + inner: Stream, +} + +#[derive(Debug)] +struct Stream { + stream_wrapper: ffi::StreamWrapper, + total_in: u64, + total_out: u64, + _marker: marker::PhantomData, +} + +unsafe impl Send for Stream {} +unsafe impl Sync for Stream {} + +trait Direction { + unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int; +} + +#[derive(Debug)] +enum DirCompress {} +#[derive(Debug)] +enum DirDecompress {} + +/// Values which indicate the form of flushing to be used when compressing or +/// decompressing in-memory data. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Flush { + /// A typical parameter for passing to compression/decompression functions, + /// this indicates that the underlying stream to decide how much data to + /// accumulate before producing output in order to maximize compression. + None = ffi::MZ_NO_FLUSH as isize, + + /// All pending output is flushed to the output buffer and the output is + /// aligned on a byte boundary so that the decompressor can get all input + /// data available so far. + /// + /// Flushing may degrade compression for some compression algorithms and so + /// it should only be used when necessary. This will complete the current + /// deflate block and follow it with an empty stored block. + Sync = ffi::MZ_SYNC_FLUSH as isize, + + /// All pending output is flushed to the output buffer, but the output is + /// not aligned to a byte boundary. + /// + /// All of the input data so far will be available to the decompressor (as + /// with `Flush::Sync`. This completes the current deflate block and follows + /// it with an empty fixed codes block that is 10 bites long, and it assures + /// that enough bytes are output in order for the decompessor to finish the + /// block before the empty fixed code block. + Partial = ffi::MZ_PARTIAL_FLUSH as isize, + + /// A deflate block is completed and emitted, as for `Flush::Sync`, but the + /// output is not aligned on a byte boundary and up to seven vits of the + /// current block are held to be written as the next byte after the next + /// deflate block is completed. + /// + /// In this case the decompressor may not be provided enough bits at this + /// point in order to complete decompression of the data provided so far to + /// the compressor, it may need to wait for the next block to be emitted. + /// This is for advanced applications that need to control the emission of + /// deflate blocks. + Block = ffi::MZ_BLOCK as isize, + + /// All output is flushed as with `Flush::Sync` and the compression state is + /// reset so decompression can restart from this point if previous + /// compressed data has been damaged or if random access is desired. + /// + /// Using this option too often can seriously degrade compression. + Full = ffi::MZ_FULL_FLUSH as isize, + + /// Pending input is processed and pending output is flushed. + /// + /// The return value may indicate that the stream is not yet done and more + /// data has yet to be processed. + Finish = ffi::MZ_FINISH as isize, +} + +/// Error returned when a decompression object finds that the input stream of +/// bytes was not a valid input stream of bytes. +#[derive(Debug)] +pub struct DataError(()); + +/// Possible status results of compressing some data or successfully +/// decompressing a block of data. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Status { + /// Indicates success. + /// + /// Means that more input may be needed but isn't available + /// and/or there' smore output to be written but the output buffer is full. + Ok, + + /// Indicates that forward progress is not possible due to input or output + /// buffers being empty. + /// + /// For compression it means the input buffer needs some more data or the + /// output buffer needs to be freed up before trying again. + /// + /// For decompression this means that more input is needed to continue or + /// the output buffer isn't large enough to contain the result. The function + /// can be called again after fixing both. + BufError, + + /// Indicates that all input has been consumed and all output bytes have + /// been written. Decompression/compression should not be called again. + /// + /// For decompression with zlib streams the adler-32 of the decompressed + /// data has also been verified. + StreamEnd, +} + +impl Compress { + /// Creates a new object ready for compressing data that it's given. + /// + /// The `level` argument here indicates what level of compression is going + /// to be performed, and the `zlib_header` argument indicates whether the + /// output data should have a zlib header or not. + pub fn new(level: Compression, zlib_header: bool) -> Compress { + unsafe { + let mut state = ffi::StreamWrapper::default(); + let ret = ffi::mz_deflateInit2(&mut *state, + level as c_int, + ffi::MZ_DEFLATED, + if zlib_header { + ffi::MZ_DEFAULT_WINDOW_BITS + } else { + -ffi::MZ_DEFAULT_WINDOW_BITS + }, + 9, + ffi::MZ_DEFAULT_STRATEGY); + debug_assert_eq!(ret, 0); + Compress { + inner: Stream { + stream_wrapper: state, + total_in: 0, + total_out: 0, + _marker: marker::PhantomData, + }, + } + } + } + + /// Returns the total number of input bytes which have been processed by + /// this compression object. + pub fn total_in(&self) -> u64 { + self.inner.total_in + } + + /// Returns the total number of output bytes which have been produced by + /// this compression object. + pub fn total_out(&self) -> u64 { + self.inner.total_out + } + + /// Quickly resets this compressor without having to reallocate anything. + /// + /// This is equivalent to dropping this object and then creating a new one. + pub fn reset(&mut self) { + let rc = unsafe { ffi::mz_deflateReset(&mut *self.inner.stream_wrapper) }; + assert_eq!(rc, ffi::MZ_OK); + + self.inner.total_in = 0; + self.inner.total_out = 0; + } + + /// Compresses the input data into the output, consuming only as much + /// input as needed and writing as much output as possible. + /// + /// The flush option can be any of the available flushing parameters. + /// + /// To learn how much data was consumed or how much output was produced, use + /// the `total_in` and `total_out` functions before/after this is called. + pub fn compress(&mut self, + input: &[u8], + output: &mut [u8], + flush: Flush) + -> Status { + let raw = &mut *self.inner.stream_wrapper; + raw.next_in = input.as_ptr() as *mut _; + raw.avail_in = input.len() as c_uint; + raw.next_out = output.as_mut_ptr(); + raw.avail_out = output.len() as c_uint; + + let rc = unsafe { ffi::mz_deflate(raw, flush as c_int) }; + + // Unfortunately the total counters provided by zlib might be only + // 32 bits wide and overflow while processing large amounts of data. + self.inner.total_in += (raw.next_in as usize - + input.as_ptr() as usize) as u64; + self.inner.total_out += (raw.next_out as usize - + output.as_ptr() as usize) as u64; + + match rc { + ffi::MZ_OK => Status::Ok, + ffi::MZ_BUF_ERROR => Status::BufError, + ffi::MZ_STREAM_END => Status::StreamEnd, + c => panic!("unknown return code: {}", c), + } + } + + /// Compresses the input data into the extra space of the output, consuming + /// only as much input as needed and writing as much output as possible. + /// + /// This function has the same semantics as `compress`, except that the + /// length of `vec` is managed by this function. This will not reallocate + /// the vector provided or attempt to grow it, so space for the output must + /// be reserved in the output vector by the caller before calling this + /// function. + pub fn compress_vec(&mut self, + input: &[u8], + output: &mut Vec, + flush: Flush) + -> Status { + let cap = output.capacity(); + let len = output.len(); + + unsafe { + let before = self.total_out(); + let ret = { + let ptr = output.as_mut_ptr().offset(len as isize); + let out = slice::from_raw_parts_mut(ptr, cap - len); + self.compress(input, out, flush) + }; + output.set_len((self.total_out() - before) as usize + len); + return ret + } + } +} + +impl Decompress { + /// Creates a new object ready for decompressing data that it's given. + /// + /// The `zlib_header` argument indicates whether the input data is expected + /// to have a zlib header or not. + pub fn new(zlib_header: bool) -> Decompress { + unsafe { + let mut state = ffi::StreamWrapper::default(); + let ret = ffi::mz_inflateInit2(&mut *state, + if zlib_header { + ffi::MZ_DEFAULT_WINDOW_BITS + } else { + -ffi::MZ_DEFAULT_WINDOW_BITS + }); + debug_assert_eq!(ret, 0); + Decompress { + inner: Stream { + stream_wrapper: state, + total_in: 0, + total_out: 0, + _marker: marker::PhantomData, + }, + } + } + } + + /// Returns the total number of input bytes which have been processed by + /// this decompression object. + pub fn total_in(&self) -> u64 { + self.inner.total_in + } + + /// Returns the total number of output bytes which have been produced by + /// this decompression object. + pub fn total_out(&self) -> u64 { + self.inner.total_out + } + + /// Decompresses the input data into the output, consuming only as much + /// input as needed and writing as much output as possible. + /// + /// The flush option provided can either be `Flush::None`, `Flush::Sync`, + /// or `Flush::Finish`. If the first call passes `Flush::Finish` it is + /// assumed that the input and output buffers are both sized large enough to + /// decompress the entire stream in a single call. + /// + /// A flush value of `Flush::Finish` indicates that there are no more source + /// bytes available beside what's already in the input buffer, and the + /// output buffer is large enough to hold the rest of the decompressed data. + /// + /// To learn how much data was consumed or how much output was produced, use + /// the `total_in` and `total_out` functions before/after this is called. + /// + /// # Errors + /// + /// If the input data to this instance of `Decompress` is not a valid + /// zlib/deflate stream then this function may return an instance of + /// `DataError` to indicate that the stream of input bytes is corrupted. + pub fn decompress(&mut self, + input: &[u8], + output: &mut [u8], + flush: Flush) + -> Result { + let raw = &mut *self.inner.stream_wrapper; + raw.next_in = input.as_ptr() as *mut u8; + raw.avail_in = input.len() as c_uint; + raw.next_out = output.as_mut_ptr(); + raw.avail_out = output.len() as c_uint; + + let rc = unsafe { ffi::mz_inflate(raw, flush as c_int) }; + + // Unfortunately the total counters provided by zlib might be only + // 32 bits wide and overflow while processing large amounts of data. + self.inner.total_in += (raw.next_in as usize - + input.as_ptr() as usize) as u64; + self.inner.total_out += (raw.next_out as usize - + output.as_ptr() as usize) as u64; + + match rc { + ffi::MZ_DATA_ERROR | + ffi::MZ_STREAM_ERROR => Err(DataError(())), + ffi::MZ_OK => Ok(Status::Ok), + ffi::MZ_BUF_ERROR => Ok(Status::BufError), + ffi::MZ_STREAM_END => Ok(Status::StreamEnd), + c => panic!("unknown return code: {}", c), + } + } + + /// Decompresses the input data into the extra space in the output vector + /// specified by `output`. + /// + /// This function has the same semantics as `decompress`, except that the + /// length of `vec` is managed by this function. This will not reallocate + /// the vector provided or attempt to grow it, so space for the output must + /// be reserved in the output vector by the caller before calling this + /// function. + /// + /// # Errors + /// + /// If the input data to this instance of `Decompress` is not a valid + /// zlib/deflate stream then this function may return an instance of + /// `DataError` to indicate that the stream of input bytes is corrupted. + pub fn decompress_vec(&mut self, + input: &[u8], + output: &mut Vec, + flush: Flush) + -> Result { + let cap = output.capacity(); + let len = output.len(); + + unsafe { + let before = self.total_out(); + let ret = { + let ptr = output.as_mut_ptr().offset(len as isize); + let out = slice::from_raw_parts_mut(ptr, cap - len); + self.decompress(input, out, flush) + }; + output.set_len((self.total_out() - before) as usize + len); + return ret + } + } + + /// Performs the equivalent of replacing this decompression state with a + /// freshly allocated copy. + /// + /// This function may not allocate memory, though, and attempts to reuse any + /// previously existing resources. + /// + /// The argument provided here indicates whether the reset state will + /// attempt to decode a zlib header first or not. + pub fn reset(&mut self, zlib_header: bool) { + self._reset(zlib_header); + } + + #[cfg(feature = "zlib")] + fn _reset(&mut self, zlib_header: bool) { + let bits = if zlib_header { + ffi::MZ_DEFAULT_WINDOW_BITS + } else { + -ffi::MZ_DEFAULT_WINDOW_BITS + }; + unsafe { + ffi::inflateReset2(&mut *self.inner.stream_wrapper, bits); + } + self.inner.total_out = 0; + self.inner.total_in = 0; + } + + #[cfg(not(feature = "zlib"))] + fn _reset(&mut self, zlib_header: bool) { + *self = Decompress::new(zlib_header); + } +} + +impl Error for DataError { + fn description(&self) -> &str { "deflate data error" } +} + +impl From for io::Error { + fn from(data: DataError) -> io::Error { + io::Error::new(io::ErrorKind::Other, data) + } +} + +impl fmt::Display for DataError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +impl Direction for DirCompress { + unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int { + ffi::mz_deflateEnd(stream) + } +} +impl Direction for DirDecompress { + unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int { + ffi::mz_inflateEnd(stream) + } +} + +impl Drop for Stream { + fn drop(&mut self) { + unsafe { + let _ = D::destroy(&mut *self.stream_wrapper); + } + } +} + +#[cfg(test)] +mod tests { + use std::io::Write; + + use write; + use {Compression, Decompress, Flush}; + + #[test] + fn issue51() { + let data = vec![ + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xb3, 0xc9, + 0x28, 0xc9, 0xcd, 0xb1, 0xe3, 0xe5, 0xb2, 0xc9, 0x48, 0x4d, 0x4c, 0xb1, + 0xb3, 0x29, 0xc9, 0x2c, 0xc9, 0x49, 0xb5, 0x33, 0x31, 0x30, 0x51, 0xf0, + 0xcb, 0x2f, 0x51, 0x70, 0xcb, 0x2f, 0xcd, 0x4b, 0xb1, 0xd1, 0x87, 0x08, + 0xda, 0xe8, 0x83, 0x95, 0x00, 0x95, 0x26, 0xe5, 0xa7, 0x54, 0x2a, 0x24, + 0xa5, 0x27, 0xe7, 0xe7, 0xe4, 0x17, 0xd9, 0x2a, 0x95, 0x67, 0x64, 0x96, + 0xa4, 0x2a, 0x81, 0x8c, 0x48, 0x4e, 0xcd, 0x2b, 0x49, 0x2d, 0xb2, 0xb3, + 0xc9, 0x30, 0x44, 0x37, 0x01, 0x28, 0x62, 0xa3, 0x0f, 0x95, 0x06, 0xd9, + 0x05, 0x54, 0x04, 0xe5, 0xe5, 0xa5, 0x67, 0xe6, 0x55, 0xe8, 0x1b, 0xea, + 0x99, 0xe9, 0x19, 0x21, 0xab, 0xd0, 0x07, 0xd9, 0x01, 0x32, 0x53, 0x1f, + 0xea, 0x3e, 0x00, 0x94, 0x85, 0xeb, 0xe4, 0xa8, 0x00, 0x00, 0x00 + ]; + + let mut decoded = Vec::with_capacity(data.len()*2); + + let mut d = Decompress::new(false); + // decompressed whole deflate stream + assert!(d.decompress_vec(&data[10..], &mut decoded, Flush::Finish).is_ok()); + + // decompress data that has nothing to do with the deflate stream (this + // used to panic) + drop(d.decompress_vec(&[0], &mut decoded, Flush::None)); + } + + #[test] + fn reset() { + let string = "hello world".as_bytes(); + let mut zlib = Vec::new(); + let mut deflate = Vec::new(); + + let comp = Compression::Default; + write::ZlibEncoder::new(&mut zlib, comp).write_all(string).unwrap(); + write::DeflateEncoder::new(&mut deflate, comp).write_all(string).unwrap(); + + let mut dst = [0; 1024]; + let mut decoder = Decompress::new(true); + decoder.decompress(&zlib, &mut dst, Flush::Finish).unwrap(); + assert_eq!(decoder.total_out(), string.len() as u64); + assert!(dst.starts_with(string)); + + decoder.reset(false); + decoder.decompress(&deflate, &mut dst, Flush::Finish).unwrap(); + assert_eq!(decoder.total_out(), string.len() as u64); + assert!(dst.starts_with(string)); + } +} diff --git a/flate2-0.2.20/src/zio.rs b/flate2-0.2.20/src/zio.rs new file mode 100644 index 000000000..358ffb326 --- /dev/null +++ b/flate2-0.2.20/src/zio.rs @@ -0,0 +1,201 @@ +use std::io::prelude::*; +use std::io; +use std::mem; + +use {Decompress, Compress, Status, Flush, DataError}; + +#[derive(Debug)] +pub struct Writer { + obj: Option, + pub data: D, + buf: Vec, +} + +pub trait Ops { + fn total_in(&self) -> u64; + fn total_out(&self) -> u64; + fn run(&mut self, input: &[u8], output: &mut [u8], flush: Flush) + -> Result; + fn run_vec(&mut self, input: &[u8], output: &mut Vec, flush: Flush) + -> Result; +} + +impl Ops for Compress { + fn total_in(&self) -> u64 { self.total_in() } + fn total_out(&self) -> u64 { self.total_out() } + fn run(&mut self, input: &[u8], output: &mut [u8], flush: Flush) + -> Result { + Ok(self.compress(input, output, flush)) + } + fn run_vec(&mut self, input: &[u8], output: &mut Vec, flush: Flush) + -> Result { + Ok(self.compress_vec(input, output, flush)) + } +} + +impl Ops for Decompress { + fn total_in(&self) -> u64 { self.total_in() } + fn total_out(&self) -> u64 { self.total_out() } + fn run(&mut self, input: &[u8], output: &mut [u8], flush: Flush) + -> Result { + self.decompress(input, output, flush) + } + fn run_vec(&mut self, input: &[u8], output: &mut Vec, flush: Flush) + -> Result { + self.decompress_vec(input, output, flush) + } +} + +pub fn read(obj: &mut R, data: &mut D, dst: &mut [u8]) -> io::Result + where R: BufRead, D: Ops +{ + loop { + let (read, consumed, ret, eof); + { + let input = try!(obj.fill_buf()); + eof = input.is_empty(); + let before_out = data.total_out(); + let before_in = data.total_in(); + let flush = if eof {Flush::Finish} else {Flush::None}; + ret = data.run(input, dst, flush); + read = (data.total_out() - before_out) as usize; + consumed = (data.total_in() - before_in) as usize; + } + obj.consume(consumed); + + match ret { + // If we haven't ready any data and we haven't hit EOF yet, + // then we need to keep asking for more data because if we + // return that 0 bytes of data have been read then it will + // be interpreted as EOF. + Ok(Status::Ok) | + Ok(Status::BufError) if read == 0 && !eof && dst.len() > 0 => { + continue + } + Ok(Status::Ok) | + Ok(Status::BufError) | + Ok(Status::StreamEnd) => return Ok(read), + + Err(..) => return Err(io::Error::new(io::ErrorKind::InvalidInput, + "corrupt deflate stream")) + } + } +} + +impl Writer { + pub fn new(w: W, d: D) -> Writer { + Writer { + obj: Some(w), + data: d, + buf: Vec::with_capacity(32 * 1024), + } + } + + pub fn finish(&mut self) -> io::Result<()> { + loop { + try!(self.dump()); + + let before = self.data.total_out(); + try!(self.data.run_vec(&[], &mut self.buf, Flush::Finish)); + if before == self.data.total_out() { + return Ok(()) + } + } + } + + pub fn replace(&mut self, w: W) -> W { + self.buf.truncate(0); + mem::replace(self.get_mut(), w) + } + + pub fn get_ref(&self) -> &W { + self.obj.as_ref().unwrap() + } + + pub fn get_mut(&mut self) -> &mut W { + self.obj.as_mut().unwrap() + } + + // Note that this should only be called if the outer object is just about + // to be consumed! + // + // (e.g. an implementation of `into_inner`) + pub fn take_inner(&mut self) -> W { + self.obj.take().unwrap() + } + + pub fn is_present(&self) -> bool { + self.obj.is_some() + } + + fn dump(&mut self) -> io::Result<()> { + // TODO: should manage this buffer not with `drain` but probably more of + // a deque-like strategy. + while self.buf.len() > 0 { + let n = try!(self.obj.as_mut().unwrap().write(&self.buf)); + if n == 0 { + return Err(io::ErrorKind::WriteZero.into()) + } + self.buf.drain(..n); + } + Ok(()) + } +} + +impl Write for Writer { + fn write(&mut self, buf: &[u8]) -> io::Result { + // miniz isn't guaranteed to actually write any of the buffer provided, + // it may be in a flushing mode where it's just giving us data before + // we're actually giving it any data. We don't want to spuriously return + // `Ok(0)` when possible as it will cause calls to write_all() to fail. + // As a result we execute this in a loop to ensure that we try our + // darndest to write the data. + loop { + try!(self.dump()); + + let before_in = self.data.total_in(); + let ret = self.data.run_vec(buf, &mut self.buf, Flush::None); + let written = (self.data.total_in() - before_in) as usize; + + if buf.len() > 0 && written == 0 && ret.is_ok() { + continue + } + return match ret { + Ok(Status::Ok) | + Ok(Status::BufError) | + Ok(Status::StreamEnd) => Ok(written), + + Err(..) => Err(io::Error::new(io::ErrorKind::InvalidInput, + "corrupt deflate stream")) + } + } + } + + fn flush(&mut self) -> io::Result<()> { + self.data.run_vec(&[], &mut self.buf, Flush::Sync).unwrap(); + + // Unfortunately miniz doesn't actually tell us when we're done with + // pulling out all the data from the internal stream. To remedy this we + // have to continually ask the stream for more memory until it doesn't + // give us a chunk of memory the same size as our own internal buffer, + // at which point we assume it's reached the end. + loop { + try!(self.dump()); + let before = self.data.total_out(); + self.data.run_vec(&[], &mut self.buf, Flush::None).unwrap(); + if before == self.data.total_out() { + break + } + } + + self.obj.as_mut().unwrap().flush() + } +} + +impl Drop for Writer { + fn drop(&mut self) { + if self.obj.is_some() { + let _ = self.finish(); + } + } +} diff --git a/flate2-0.2.20/src/zlib/bufread.rs b/flate2-0.2.20/src/zlib/bufread.rs new file mode 100644 index 000000000..a21a905f6 --- /dev/null +++ b/flate2-0.2.20/src/zlib/bufread.rs @@ -0,0 +1,259 @@ +use std::io::prelude::*; +use std::io; +use std::mem; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use zio; +use {Compress, Decompress}; + +/// A ZLIB encoder, or compressor. +/// +/// This structure implements a [`BufRead`] interface and will read uncompressed +/// data from an underlying stream and emit a stream of compressed data. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use flate2::Compression; +/// use flate2::bufread::ZlibEncoder; +/// use std::fs::File; +/// use std::io::BufReader; +/// +/// // Use a buffered file to compress contents into a Vec +/// +/// # fn open_hello_world() -> std::io::Result> { +/// let f = File::open("examples/hello_world.txt")?; +/// let b = BufReader::new(f); +/// let mut z = ZlibEncoder::new(b, Compression::Fast); +/// let mut buffer = Vec::new(); +/// z.read_to_end(&mut buffer)?; +/// # Ok(buffer) +/// # } +/// ``` +#[derive(Debug)] +pub struct ZlibEncoder { + obj: R, + data: Compress, +} + + +impl ZlibEncoder { + /// Creates a new encoder which will read uncompressed data from the given + /// stream and emit the compressed stream. + pub fn new(r: R, level: ::Compression) -> ZlibEncoder { + ZlibEncoder { + obj: r, + data: Compress::new(level, true), + } + } +} + +pub fn reset_encoder_data(zlib: &mut ZlibEncoder) { + zlib.data.reset() +} + +impl ZlibEncoder { + /// Resets the state of this encoder entirely, swapping out the input + /// stream for another. + /// + /// This function will reset the internal state of this encoder and replace + /// the input stream with the one provided, returning the previous input + /// stream. Future data read from this encoder will be the compressed + /// version of `r`'s data. + pub fn reset(&mut self, r: R) -> R { + reset_encoder_data(self); + mem::replace(&mut self.obj, r) + } + + /// Acquires a reference to the underlying reader + pub fn get_ref(&self) -> &R { + &self.obj + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + &mut self.obj + } + + /// Consumes this encoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.obj + } + + /// Returns the number of bytes that have been read into this compressor. + /// + /// Note that not all bytes read from the underlying object may be accounted + /// for, there may still be some active buffering. + pub fn total_in(&self) -> u64 { + self.data.total_in() + } + + /// Returns the number of bytes that the compressor has produced. + /// + /// Note that not all bytes may have been read yet, some may still be + /// buffered. + pub fn total_out(&self) -> u64 { + self.data.total_out() + } +} + +impl Read for ZlibEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + zio::read(&mut self.obj, &mut self.data, buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for ZlibEncoder {} + +impl Write for ZlibEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for ZlibEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} + +/// A ZLIB decoder, or decompressor. +/// +/// This structure implements a [`BufRead`] interface and takes a stream of +/// compressed data as input, providing the decompressed data when read from. +/// +/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::ZlibEncoder; +/// use flate2::bufread::ZlibDecoder; +/// +/// # fn main() { +/// # let mut e = ZlibEncoder::new(Vec::new(), Compression::Default); +/// # e.write(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_bufreader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Zlib Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements BufRead +/// +/// fn decode_bufreader(bytes: Vec) -> io::Result { +/// let mut z = ZlibDecoder::new(&bytes[..]); +/// let mut s = String::new(); +/// z.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct ZlibDecoder { + obj: R, + data: Decompress, +} + +impl ZlibDecoder { + /// Creates a new decoder which will decompress data read from the given + /// stream. + pub fn new(r: R) -> ZlibDecoder { + ZlibDecoder { + obj: r, + data: Decompress::new(true), + } + } +} + +pub fn reset_decoder_data(zlib: &mut ZlibDecoder) { + zlib.data = Decompress::new(true); +} + +impl ZlibDecoder { + /// Resets the state of this decoder entirely, swapping out the input + /// stream for another. + /// + /// This will reset the internal state of this decoder and replace the + /// input stream with the one provided, returning the previous input + /// stream. Future data read from this decoder will be the decompressed + /// version of `r`'s data. + pub fn reset(&mut self, r: R) -> R { + reset_decoder_data(self); + mem::replace(&mut self.obj, r) + } + + /// Acquires a reference to the underlying stream + pub fn get_ref(&self) -> &R { + &self.obj + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + &mut self.obj + } + + /// Consumes this decoder, returning the underlying reader. + pub fn into_inner(self) -> R { + self.obj + } + + /// Returns the number of bytes that the decompressor has consumed. + /// + /// Note that this will likely be smaller than what the decompressor + /// actually read from the underlying stream due to buffering. + pub fn total_in(&self) -> u64 { + self.data.total_in() + } + + /// Returns the number of bytes that the decompressor has produced. + pub fn total_out(&self) -> u64 { + self.data.total_out() + } +} + +impl Read for ZlibDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + zio::read(&mut self.obj, &mut self.data, into) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for ZlibDecoder {} + +impl Write for ZlibDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for ZlibDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} diff --git a/flate2-0.2.20/src/zlib/mod.rs b/flate2-0.2.20/src/zlib/mod.rs new file mode 100644 index 000000000..b04e40b82 --- /dev/null +++ b/flate2-0.2.20/src/zlib/mod.rs @@ -0,0 +1,164 @@ +pub mod bufread; +pub mod read; +pub mod write; + + +#[cfg(test)] +mod tests { + use std::io::prelude::*; + use std::io; + + use rand::{thread_rng, Rng}; + + use zlib::{read, write}; + use Compression::Default; + + #[test] + fn roundtrip() { + let mut real = Vec::new(); + let mut w = write::ZlibEncoder::new(Vec::new(), Default); + let v = thread_rng().gen_iter::().take(1024).collect::>(); + for _ in 0..200 { + let to_write = &v[..thread_rng().gen_range(0, v.len())]; + real.extend(to_write.iter().map(|x| *x)); + w.write_all(to_write).unwrap(); + } + let result = w.finish().unwrap(); + let mut r = read::ZlibDecoder::new(&result[..]); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert!(ret == real); + } + + #[test] + fn drop_writes() { + let mut data = Vec::new(); + write::ZlibEncoder::new(&mut data, Default) + .write_all(b"foo") + .unwrap(); + let mut r = read::ZlibDecoder::new(&data[..]); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert!(ret == b"foo"); + } + + #[test] + fn total_in() { + let mut real = Vec::new(); + let mut w = write::ZlibEncoder::new(Vec::new(), Default); + let v = thread_rng().gen_iter::().take(1024).collect::>(); + for _ in 0..200 { + let to_write = &v[..thread_rng().gen_range(0, v.len())]; + real.extend(to_write.iter().map(|x| *x)); + w.write_all(to_write).unwrap(); + } + let mut result = w.finish().unwrap(); + + let result_len = result.len(); + + for _ in 0..200 { + result.extend(v.iter().map(|x| *x)); + } + + let mut r = read::ZlibDecoder::new(&result[..]); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert!(ret == real); + assert_eq!(r.total_in(), result_len as u64); + } + + #[test] + fn roundtrip2() { + let v = thread_rng() + .gen_iter::() + .take(1024 * 1024) + .collect::>(); + let mut r = read::ZlibDecoder::new(read::ZlibEncoder::new(&v[..], Default)); + let mut ret = Vec::new(); + r.read_to_end(&mut ret).unwrap(); + assert_eq!(ret, v); + } + + #[test] + fn roundtrip3() { + let v = thread_rng() + .gen_iter::() + .take(1024 * 1024) + .collect::>(); + let mut w = write::ZlibEncoder::new(write::ZlibDecoder::new(Vec::new()), Default); + w.write_all(&v).unwrap(); + let w = w.finish().unwrap().finish().unwrap(); + assert!(w == v); + } + + #[test] + fn reset_decoder() { + let v = thread_rng() + .gen_iter::() + .take(1024 * 1024) + .collect::>(); + let mut w = write::ZlibEncoder::new(Vec::new(), Default); + w.write_all(&v).unwrap(); + let data = w.finish().unwrap(); + + { + let (mut a, mut b, mut c) = (Vec::new(), Vec::new(), Vec::new()); + let mut r = read::ZlibDecoder::new(&data[..]); + r.read_to_end(&mut a).unwrap(); + r.reset(&data); + r.read_to_end(&mut b).unwrap(); + + let mut r = read::ZlibDecoder::new(&data[..]); + r.read_to_end(&mut c).unwrap(); + assert!(a == b && b == c && c == v); + } + + { + let mut w = write::ZlibDecoder::new(Vec::new()); + w.write_all(&data).unwrap(); + let a = w.reset(Vec::new()).unwrap(); + w.write_all(&data).unwrap(); + let b = w.finish().unwrap(); + + let mut w = write::ZlibDecoder::new(Vec::new()); + w.write_all(&data).unwrap(); + let c = w.finish().unwrap(); + assert!(a == b && b == c && c == v); + } + } + + #[test] + fn bad_input() { + // regress tests: previously caused a panic on drop + let mut out: Vec = Vec::new(); + let data: Vec = (0..255).cycle().take(1024).collect(); + let mut w = write::ZlibDecoder::new(&mut out); + match w.write_all(&data[..]) { + Ok(_) => panic!("Expected an error to be returned!"), + Err(e) => assert_eq!(e.kind(), io::ErrorKind::InvalidInput), + } + } + + #[test] + fn qc_reader() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(v: Vec) -> bool { + let mut r = read::ZlibDecoder::new(read::ZlibEncoder::new(&v[..], Default)); + let mut v2 = Vec::new(); + r.read_to_end(&mut v2).unwrap(); + v == v2 + } + } + + #[test] + fn qc_writer() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(v: Vec) -> bool { + let mut w = write::ZlibEncoder::new(write::ZlibDecoder::new(Vec::new()), Default); + w.write_all(&v).unwrap(); + v == w.finish().unwrap().finish().unwrap() + } + } +} diff --git a/flate2-0.2.20/src/zlib/read.rs b/flate2-0.2.20/src/zlib/read.rs new file mode 100644 index 000000000..a2eece78d --- /dev/null +++ b/flate2-0.2.20/src/zlib/read.rs @@ -0,0 +1,266 @@ +use std::io::prelude::*; +use std::io; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use bufreader::BufReader; +use super::bufread; + +/// A ZLIB encoder, or compressor. +/// +/// This structure implements a [`Read`] interface and will read uncompressed +/// data from an underlying stream and emit a stream of compressed data. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use flate2::Compression; +/// use flate2::read::ZlibEncoder; +/// use std::fs::File; +/// +/// // Open example file and compress the contents using Read interface +/// +/// # fn open_hello_world() -> std::io::Result> { +/// let f = File::open("examples/hello_world.txt")?; +/// let mut z = ZlibEncoder::new(f, Compression::Fast); +/// let mut buffer = [0;50]; +/// let byte_count = z.read(&mut buffer)?; +/// # Ok(buffer[0..byte_count].to_vec()) +/// # } +/// ``` +#[derive(Debug)] +pub struct ZlibEncoder { + inner: bufread::ZlibEncoder>, +} + +impl ZlibEncoder { + /// Creates a new encoder which will read uncompressed data from the given + /// stream and emit the compressed stream. + pub fn new(r: R, level: ::Compression) -> ZlibEncoder { + ZlibEncoder { + inner: bufread::ZlibEncoder::new(BufReader::new(r), level), + } + } +} + +impl ZlibEncoder { + /// Resets the state of this encoder entirely, swapping out the input + /// stream for another. + /// + /// This function will reset the internal state of this encoder and replace + /// the input stream with the one provided, returning the previous input + /// stream. Future data read from this encoder will be the compressed + /// version of `r`'s data. + /// + /// Note that there may be currently buffered data when this function is + /// called, and in that case the buffered data is discarded. + pub fn reset(&mut self, r: R) -> R { + super::bufread::reset_encoder_data(&mut self.inner); + self.inner.get_mut().reset(r) + } + + /// Acquires a reference to the underlying stream + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this encoder, returning the underlying reader. + /// + /// Note that there may be buffered bytes which are not re-acquired as part + /// of this transition. It's recommended to only call this function after + /// EOF has been reached. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } + + /// Returns the number of bytes that have been read into this compressor. + /// + /// Note that not all bytes read from the underlying object may be accounted + /// for, there may still be some active buffering. + pub fn total_in(&self) -> u64 { + self.inner.total_in() + } + + /// Returns the number of bytes that the compressor has produced. + /// + /// Note that not all bytes may have been read yet, some may still be + /// buffered. + pub fn total_out(&self) -> u64 { + self.inner.total_out() + } +} + +impl Read for ZlibEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for ZlibEncoder {} + +impl Write for ZlibEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for ZlibEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} + +/// A ZLIB decoder, or decompressor. +/// +/// This structure implements a [`Read`] interface and takes a stream of +/// compressed data as input, providing the decompressed data when read from. +/// +/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::ZlibEncoder; +/// use flate2::read::ZlibDecoder; +/// +/// # fn main() { +/// # let mut e = ZlibEncoder::new(Vec::new(), Compression::Default); +/// # e.write(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Zlib Encoded vector of bytes and returns a string or error +/// // Here &[u8] implements Read +/// +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut z = ZlibDecoder::new(&bytes[..]); +/// let mut s = String::new(); +/// z.read_to_string(&mut s)?; +/// Ok(s) +/// } +/// ``` +#[derive(Debug)] +pub struct ZlibDecoder { + inner: bufread::ZlibDecoder>, +} + + +impl ZlibDecoder { + /// Creates a new decoder which will decompress data read from the given + /// stream. + pub fn new(r: R) -> ZlibDecoder { + ZlibDecoder::new_with_buf(r, vec![0; 32 * 1024]) + } + + /// Same as `new`, but the intermediate buffer for data is specified. + /// + /// Note that the specified buffer will only be used up to its current + /// length. The buffer's capacity will also not grow over time. + pub fn new_with_buf(r: R, buf: Vec) -> ZlibDecoder { + ZlibDecoder { + inner: bufread::ZlibDecoder::new(BufReader::with_buf(buf, r)), + } + } +} + +impl ZlibDecoder { + /// Resets the state of this decoder entirely, swapping out the input + /// stream for another. + /// + /// This will reset the internal state of this decoder and replace the + /// input stream with the one provided, returning the previous input + /// stream. Future data read from this decoder will be the decompressed + /// version of `r`'s data. + /// + /// Note that there may be currently buffered data when this function is + /// called, and in that case the buffered data is discarded. + pub fn reset(&mut self, r: R) -> R { + super::bufread::reset_decoder_data(&mut self.inner); + self.inner.get_mut().reset(r) + } + + /// Acquires a reference to the underlying stream + pub fn get_ref(&self) -> &R { + self.inner.get_ref().get_ref() + } + + /// Acquires a mutable reference to the underlying stream + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + self.inner.get_mut().get_mut() + } + + /// Consumes this decoder, returning the underlying reader. + /// + /// Note that there may be buffered bytes which are not re-acquired as part + /// of this transition. It's recommended to only call this function after + /// EOF has been reached. + pub fn into_inner(self) -> R { + self.inner.into_inner().into_inner() + } + + /// Returns the number of bytes that the decompressor has consumed. + /// + /// Note that this will likely be smaller than what the decompressor + /// actually read from the underlying stream due to buffering. + pub fn total_in(&self) -> u64 { + self.inner.total_in() + } + + /// Returns the number of bytes that the decompressor has produced. + pub fn total_out(&self) -> u64 { + self.inner.total_out() + } +} + +impl Read for ZlibDecoder { + fn read(&mut self, into: &mut [u8]) -> io::Result { + self.inner.read(into) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for ZlibDecoder {} + +impl Write for ZlibDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.get_mut().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.get_mut().flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for ZlibDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + self.get_mut().shutdown() + } +} diff --git a/flate2-0.2.20/src/zlib/write.rs b/flate2-0.2.20/src/zlib/write.rs new file mode 100644 index 000000000..52e4fc28e --- /dev/null +++ b/flate2-0.2.20/src/zlib/write.rs @@ -0,0 +1,351 @@ +use std::io::prelude::*; +use std::io; + +#[cfg(feature = "tokio")] +use futures::Poll; +#[cfg(feature = "tokio")] +use tokio_io::{AsyncRead, AsyncWrite}; + +use zio; +use {Compress, Decompress}; + +/// A ZLIB encoder, or compressor. +/// +/// This structure implements a [`Write`] interface and takes a stream of +/// uncompressed data, writing the compressed data to the wrapped writer. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use flate2::Compression; +/// use flate2::write::ZlibEncoder; +/// +/// // Vec implements Write, assigning the compressed bytes of sample string +/// +/// # fn zlib_encoding() -> std::io::Result<()> { +/// let mut e = ZlibEncoder::new(Vec::new(), Compression::Default); +/// e.write(b"Hello World")?; +/// let compressed = e.finish()?; +/// # Ok(()) +/// # } +/// ``` +#[derive(Debug)] +pub struct ZlibEncoder { + inner: zio::Writer, +} + + +impl ZlibEncoder { + /// Creates a new encoder which will write compressed data to the stream + /// given at the given compression level. + /// + /// When this encoder is dropped or unwrapped the final pieces of data will + /// be flushed. + pub fn new(w: W, level: ::Compression) -> ZlibEncoder { + ZlibEncoder { + inner: zio::Writer::new(w, Compress::new(level, true)), + } + } + + /// Acquires a reference to the underlying writer. + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Acquires a mutable reference to the underlying writer. + /// + /// Note that mutating the output/input state of the stream may corrupt this + /// object, so care must be taken when using this method. + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Resets the state of this encoder entirely, swapping out the output + /// stream for another. + /// + /// This function will finish encoding the current stream into the current + /// output stream before swapping out the two output streams. + /// + /// After the current stream has been finished, this will reset the internal + /// state of this encoder and replace the output stream with the one + /// provided, returning the previous output stream. Future data written to + /// this encoder will be the compressed into the stream `w` provided. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn reset(&mut self, w: W) -> io::Result { + try!(self.inner.finish()); + self.inner.data.reset(); + Ok(self.inner.replace(w)) + } + + /// Attempt to finish this output stream, writing out final chunks of data. + /// + /// Note that this function can only be used once data has finished being + /// written to the output stream. After this function is called then further + /// calls to `write` may result in a panic. + /// + /// # Panics + /// + /// Attempts to write data to this stream may result in a panic after this + /// function is called. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn try_finish(&mut self) -> io::Result<()> { + self.inner.finish() + } + + /// Consumes this encoder, flushing the output stream. + /// + /// This will flush the underlying data stream, close off the compressed + /// stream and, if successful, return the contained writer. + /// + /// Note that this function may not be suitable to call in a situation where + /// the underlying stream is an asynchronous I/O stream. To finish a stream + /// the `try_finish` (or `shutdown`) method should be used instead. To + /// re-acquire ownership of a stream it is safe to call this method after + /// `try_finish` or `shutdown` has returned `Ok`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn finish(mut self) -> io::Result { + try!(self.inner.finish()); + Ok(self.inner.take_inner()) + } + + /// Consumes this encoder, flushing the output stream. + /// + /// This will flush the underlying data stream and then return the contained + /// writer if the flush succeeded. + /// The compressed stream will not closed but only flushed. This + /// means that obtained byte array can by extended by another deflated + /// stream. To close the stream add the two bytes 0x3 and 0x0. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn flush_finish(mut self) -> io::Result { + try!(self.inner.flush()); + Ok(self.inner.take_inner()) + } + + /// Returns the number of bytes that have been written to this compresor. + /// + /// Note that not all bytes written to this object may be accounted for, + /// there may still be some active buffering. + pub fn total_in(&self) -> u64 { + self.inner.data.total_in() + } + + /// Returns the number of bytes that the compressor has produced. + /// + /// Note that not all bytes may have been written yet, some may still be + /// buffered. + pub fn total_out(&self) -> u64 { + self.inner.data.total_out() + } +} + +impl Write for ZlibEncoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for ZlibEncoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + try_nb!(self.try_finish()); + self.get_mut().shutdown() + } +} + +impl Read for ZlibEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.get_mut().read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for ZlibEncoder {} + + +/// A ZLIB decoder, or decompressor. +/// +/// This structure implements a [`Write`] and will emit a stream of decompressed +/// data when fed a stream of compressed data. +/// +/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html +/// +/// # Examples +/// +/// ``` +/// use std::io::prelude::*; +/// use std::io; +/// # use flate2::Compression; +/// # use flate2::write::ZlibEncoder; +/// use flate2::write::ZlibDecoder; +/// +/// # fn main() { +/// # let mut e = ZlibEncoder::new(Vec::new(), Compression::Default); +/// # e.write(b"Hello World").unwrap(); +/// # let bytes = e.finish().unwrap(); +/// # println!("{}", decode_reader(bytes).unwrap()); +/// # } +/// # +/// // Uncompresses a Zlib Encoded vector of bytes and returns a string or error +/// // Here Vec implements Write +/// +/// fn decode_reader(bytes: Vec) -> io::Result { +/// let mut writer = Vec::new(); +/// let mut z = ZlibDecoder::new(writer); +/// z.write(&bytes[..])?; +/// writer = z.finish()?; +/// let return_string = String::from_utf8(writer).expect("String parsing error"); +/// Ok(return_string) +/// } +/// ``` +#[derive(Debug)] +pub struct ZlibDecoder { + inner: zio::Writer, +} + + +impl ZlibDecoder { + /// Creates a new decoder which will write uncompressed data to the stream. + /// + /// When this decoder is dropped or unwrapped the final pieces of data will + /// be flushed. + pub fn new(w: W) -> ZlibDecoder { + ZlibDecoder { + inner: zio::Writer::new(w, Decompress::new(true)), + } + } + + /// Acquires a reference to the underlying writer. + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Acquires a mutable reference to the underlying writer. + /// + /// Note that mutating the output/input state of the stream may corrupt this + /// object, so care must be taken when using this method. + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Resets the state of this decoder entirely, swapping out the output + /// stream for another. + /// + /// This will reset the internal state of this decoder and replace the + /// output stream with the one provided, returning the previous output + /// stream. Future data written to this decoder will be decompressed into + /// the output stream `w`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn reset(&mut self, w: W) -> io::Result { + try!(self.inner.finish()); + self.inner.data = Decompress::new(true); + Ok(self.inner.replace(w)) + } + + /// Attempt to finish this output stream, writing out final chunks of data. + /// + /// Note that this function can only be used once data has finished being + /// written to the output stream. After this function is called then further + /// calls to `write` may result in a panic. + /// + /// # Panics + /// + /// Attempts to write data to this stream may result in a panic after this + /// function is called. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn try_finish(&mut self) -> io::Result<()> { + self.inner.finish() + } + + /// Consumes this encoder, flushing the output stream. + /// + /// This will flush the underlying data stream and then return the contained + /// writer if the flush succeeded. + /// + /// Note that this function may not be suitable to call in a situation where + /// the underlying stream is an asynchronous I/O stream. To finish a stream + /// the `try_finish` (or `shutdown`) method should be used instead. To + /// re-acquire ownership of a stream it is safe to call this method after + /// `try_finish` or `shutdown` has returned `Ok`. + /// + /// # Errors + /// + /// This function will perform I/O to complete this stream, and any I/O + /// errors which occur will be returned from this function. + pub fn finish(mut self) -> io::Result { + try!(self.inner.finish()); + Ok(self.inner.take_inner()) + } + + /// Returns the number of bytes that the decompressor has consumed for + /// decompression. + /// + /// Note that this will likely be smaller than the number of bytes + /// successfully written to this stream due to internal buffering. + pub fn total_in(&self) -> u64 { + self.inner.data.total_in() + } + + /// Returns the number of bytes that the decompressor has written to its + /// output stream. + pub fn total_out(&self) -> u64 { + self.inner.data.total_out() + } +} + +impl Write for ZlibDecoder { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for ZlibDecoder { + fn shutdown(&mut self) -> Poll<(), io::Error> { + try_nb!(self.inner.finish()); + self.inner.get_mut().shutdown() + } +} + +impl Read for ZlibDecoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.get_mut().read(buf) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for ZlibDecoder {} diff --git a/flate2-0.2.20/tests/corrupt-file.gz b/flate2-0.2.20/tests/corrupt-file.gz new file mode 100644 index 0000000000000000000000000000000000000000..159333b032751969263eeb152e7e94782ab2cd39 GIT binary patch literal 7128 zcmeH}3`T8Bd^E~*{sR93UWTs`tIH^whgwc1l%>Czl5mp~aWyj6i8WXLt$movJ+e~8!|2g5T~UafXuTIJu# zoS~3m6PA$4Q;uFDI8m7>q+XZ&N^Gjzdn>6v%OFv?Go}67YjH_mY)Uz#0=%;*6Dqa? z?t{I-75TdNvQ}L~-ONn8cU`PXs{TyB{yv!8>iJf!Mw89_!sc@KR`fbp5@X0!>iZ}E zYU7oHq?2~Nqnbz5>o@hi;+AB%A0ZXE_WY~7dEqw&4lqG@d->r>wd4=; z_frA~ie+z1GGz$%NHbFmqzZ;Zze*!6^g;4%q)jqg+Pi9@i+61o#ucZn*BT|$yF=?n zI(#41LL^L85hEST#S{Ul8y5^~C_dtxGu%Vf%`QdZ1+nISvfpcr5x%!uN!98-In?; z3fFx^x(n8gMKWrpOZArTc=w&9$UJ!Y0p|Nj7B<3J2=mswps}|MMm&;^SQEYYn5xD!=rxs7sS`MxHsb6xrd7*UOdwC zan!!BbV|cCVea9d$fT_s^Zg&A|HtV6az^bG`rbnOYI*L7wz+)T)WX#YfJ93Jj5fl& zS0bt*EfBpC7)nF13u-+2opxJ zmoG1tJWIpk1HB&#KMXZrn329jVpn`EB~2e|6Nc?ymZ-pjzQU6Fx|7jFWYleZ@8s)! z7K$HI5y>px!wb)u6~hrYar4SjhrDM^;^t4#2QygOu~w2a zJR7mAb!$X;S_vCs!AwmB+|5PvS(igNfgT(oYb~V4E0S0xf7U9UjrMt0 z%+}w!%GY%tt?CUA&@(&Y+TPCMW5Z2DglRF}sgkg0cI@edoUkuPmzIy=_Xvv_qvKi`y5Us;0F?Br zGFciYoHX26hX2)0;V}h&W4f@hyo8>z()gpJtp^|RMn|m|@fnH9ZGgnACk%3N=>_J) z6nZx|pL4>qEeRgKmO+(Yh-~TeJ*4%1gogF|u7EoJJ5k z9abxxtAP}LUe`ddQGx_NJ7suR@}1HdsW{B=i$RRXBZ`&Prw(iegqQbUy6?ZyD%)x$ zQax!hmr0f|W=FafQP{Pz0>E3X-!kk`BlEx86iHDSWk_nAiHpRH&DEC;cGR&h>-Tcf z?VYuDYYCbkt>kt-Hd@hNYB%b}-`L)ljeetz(ZRb& zvVUcpY(xMGf6@G%mQ|E^B@}A33uh}r>8%cmyDcY&3`MiCN`o z*nz~wRPFAf9NVoa` zMUCVE$tLl!(Py!({W$r}&{IdAEI-1I1Duqrs<$SZ(=L?_(%VNrU0%Hu;if+CU|_VD z&4`;IZ|3v~36GK2Ze|^6TXcEYtTGBP2zebNKO~v_0+;=%U*-7%>GA}4CLmZ^1Dj>R zcDGz2d3g)}Y84ubi-8gLTDt$Fp-GojwmHuLlGHC4Z=uar6jHlNzW|V`hGqLSA8&yK zj}{>ZRBZbXU;eEUN@k#5ESk3=9-T(ZRk_^U@9CCa6QegMF+kI`3MX@z36@39ET(8| zaCntuc*d3l+T6G#RyM%HI2~$QoBh-rl~v}=g&gXOv+qvDaZFfcqT>MfkRK`z?N#2c zPnXN(&0K05QDOAk97_rWL@}&`$bXV+rl?ZHw@{x0P$F4rMImDlV!Mc2fk#8SfzSwD0G;ShnlK?Ei-PTybHhVDw=-qP&3!7Jcd1*ws`YANBfnu$!J@G)) z%l;wHSObFhxB(hSlN*Aq#U)p_>TLtPtbUN8(`Q3|)t@=Pf|>d&SK;dVc4KW`z%>lh z1D6f`dNgWW|O1iRD_&F;;S|n_|+d$TH3pxmfwsY7*fG)I_&$#jK72o)^3$V z<%X5(^fw$Wm58T5<4U(8-=smD3Y6D5(QL&@g&P3SpOYq}>Cu5ystYC6zciA1W6`U0 zqaR38UH1q6DCN`GX$BgE!}x(HM-ry*i(k#Tg}h$eH`0`k<qq${E>m!BjEW zTl=KdJ&a`eI&Ds3^&UpYe`GnAd@FF7vU8c^!~_->k-#;9@9kZ zbhBxQ#s3d0ACFaE$t~pu7bn29;^L7?#6iB{J65VS*7@>#HS(Oq1S=Qr!HjC)vrU3s zdADdKB(}#TVl~C(g(~uxcrKC{7o0xOdvGK8{YOs|8=x&D`m+#ulC5&DU(+PqRqS-} z!ByF14mlMEbds>!glW4Q6$lb9i&s(fK$~Ax-C0v9&&KjhaMBSPnz71IAnl0>XRFPt z)zx4?q3)2_b8d?28haZ54wLg70B;TJ^xWN;-KEd76#&|vB?8kS4K6-cDO+!tYmTbl z_B=_GW{tX;$+*Ln#{BL-1NjBT0=Q(F6~>O$&K!nGCCV@tG_NoNzrb^PK%MBZv@}PS zvrZJPcXhVx6f2!DEfuH^R8IqlsPohoC%unUFMQ!GR85Ax?#cseqDNy}6-L3>KwcS* ze57)@uOhaH0&n@>=SrYombbDxSWGBz^UoP*Vp?4S1`6UZ_8mmYyc@}76j@^vo$pm0 zb*bZI^ogAE+v5NTJHMoBD#-iJ5yhA`Yw^>bx)`PU>Lf%v`+f`dAoN-FC+-!`ysW~t z`^c?gB{N_BDd6Vy&vvS*U3Zgg4;hgT+!2)%Hip6SX7BydSJ%}E$^G5u=yX!Gji;H| zir)rN)h++kVmlvpAON;tdoS)Myur}@gFv2vOz7y{q~%QbL+VIype{pkAsG$rL6@nv zUGvT9a>qYuAMSe}y?hs|!LKnO(zfF`EPXS*7NJNJ1rAK?kjgSvN&{`0I7x1f^@KN& zVT}ez)@)!?ZucD1gYpaBG;=oNmjJGJ&X764I>u+iEesH-zW#0r)EzrBlYrqIo3|dD z_?(E5SQ@Y%!<%A zTw67eF_U;Ye5iWun6BtXDi-3Aw-fO@2F&TS_Rpl9_Y*Ciikp9Vs~&UYHHbPz0;#Iy zK?=Wh!l}FySFiSaKVP{MuYt3fWY{pSxru!2Pf~1GZq(6g!=3B4p&6%kdTS^- z)(?Na{IMI(QOze5IW;#?`W_?qQ!L5$Ijik*`_uAC%x=a`0Wld11rt#b^2~ zhrY-ycsx*m4!vM4!=fU-Y%o9)KY>W*=t9*oOL4JZcP;7IPN zv+_PYO>Z7|7ew}4SdjXd?=+iM;WdkKjXYDbsKLIugwQT-&X&h%mS8uPE@r4XOK@O& zYZJlIdPzXcS-to0=ury*F+n~4RY$$hG96B?Y?{q$#O)$61Sl-U7^!inPi>o`Uh8Qm zy{}Kb2@VP$EKc2{D;~jKxFYt3FcrH**2dXiCY7WxfiL56#CW_ zfDjntb2K%%(Hcmj!|h<%L3G~NGXHbi&3~&c&*lYu^KCgYaYQgwJ77$f9+OW5*h)-x ziUknR!aIHf#4j8kbB=|?8WkRdw$AuwS`IKImREzK-w6z_qR71rQP@4i8r*x@3eN#E1?i7+pm1^ud3V*FKH**wPf8@W}cz z)~~Wk=M6n<(Wex?6MX+!f__J&A^IsWWa7(|%^2q*U8(A52|B7LP;=LBbtY)$K2<;R zj#USgu~n+t<_n6EKbdRIr7O2e?X=*zyf;HO#nb06JBQCAXcN%1t%(@eO~z z*;cm$Q5FIe3>~(cL=}=VFM_|E%M5qH3E~eqIH)41%{KBJS&1J+$#6*EDC%tEl8=_@ zvWzM;r@|qWw@8TF+8cT!1qGYsKB);p@>}0Bf^PWBUo}sjJyJFbL=fQikll@tYWX~Q z@rAE*X3RFRuAGjv4SBMb{QbQL3W0kl`Z7Rsv4SwdBoRfs6rCjEb+@T%kE_;yV%WU< zo#P#vSv`y8Aq z8*X>ztqX);Ffmt z1o*B~%hjB%bU!?lGB1HH$CN*84aM~6c_p<6s9k0OQr{OGd zNxyZQ;+_QjCnb)vrVH`~K78Is3|rG!ph)gStC>K;Ovn=<8y*llPUG$f*eVgv(v$Bt z7IM4M@(MEf0dyN#r14C)Bj_QC2wrE@Jsq;Mu3Nl+(cUD4W|YJ6T>O*DxP?9OWF^(#!Ob+-EC%bHeisX2K`|~;B>p^I`r`OuxmZ975&80 zCceZo?YLoWvISWZxi+?-Z9t0yOE>XWCQiv&rS~+B{m`bnh+lf0QX-A;G9fM}7azE` zE?ZG4+h6uqY~+@UtVX6&gH2Ijjni`{7M*X6_Nl3~5=&YSbR6 zzvmcFD6N56{3LOdxg^7~LgRg>l;*9)xAX)$eF|?QXs-*Zf#yBBOWLOS8z;vR+shu9 zB<_qLG-h~9$SJ>06J63(zL$o~A z>zAX+)N;!t6r>WV1>9VUI!kd}O}aRC{_&u8-6x?gQ9Byw>+ajtvEr_w8>_g_G>0P> zvZVUggA}WZ-vxU0Z3dTlywC>OYIGU52PTQW6Ose!BvVvZ#;ND;tKI$XtK~!TA zm71(3{tX|x(k-M;7Fvx|$7pnXABLlO+~u3EbNrvTb1Ur1iE^7!l;2R3*5bFl#Ta^| zDF*$OifQakLq7ilRUJ$F%q=J+>MtQLw0~i&6FD#sT+!uo>)lELS>@!ypZd{t(wK$R zJPrI-*wVk$NZ3x+w%Jx9!os{o`zLxHj+m2)kJ>yODHD|71ifL%i1+_N)!d>_wYgnr z5DSbfK%m6t0w1!qZ+q_sslBpIlrK3PunDEhPaVDkR@)$%Lc`!M$Su}6Qql`Trp*C(~rdCId~1;;f?28aCcFVxBT|gpd(4CR{1^lVJ_WQ{|8`uM_fH)`BKH)i18)lVjMZnVD?|)u`HlQ2u z?zne}#@nT0El~fAqS=k)omrtV6OP;i-!qAjk%i(7rIW4N*RY8 zv+xu4N?D*qbsf!;Xwm4M+B`Lm^a;m5sWmk3_%-fny>M0>_XBHsWFV@=DE03P#J@dd zwSL^YEsSYfdm4ZsG32i~xf|45QD+Ux;unIol(f_clHUyj_?mwW;yZ@#H4 zXz$K1RyzXfoN%mvSxnP~5&Un)(iEb0$=-51EI@PXxj_vzflSsEv0ht#qA@VZ_sy!# zdsY734fuyd-f}zGudC7xMIh< zKhwwdw7E%xNskh~(&rw7t9Cx=jm)bLWa-#h>l?qz>SOWM?A#_+SsAbOx>TQ{Fm;BH zlN$10+O(#c9J2e0Y&`bcmKVP)?N+w}WE)0rJTWB3`Og1*P+g&%b$83cWWK;mOq|5E z_WtaiPks#ille$Zx!BBe`$TnqebIq@;n4Ej1lcY&=iQ0$EZ|k-81`{+l~7BQP(@qQ#Bg-$mdb)J>nF% zUOVO}tdb1;#3-iVIp-209%K|l@ugP=n~cE^OFTlrTOa0KqWa4`d&as3Vrtha{xDjW LalHo10|5UIqgUPt literal 0 HcmV?d00001 diff --git a/flate2-0.2.20/tests/early-flush.rs b/flate2-0.2.20/tests/early-flush.rs new file mode 100644 index 000000000..70c10673f --- /dev/null +++ b/flate2-0.2.20/tests/early-flush.rs @@ -0,0 +1,20 @@ +extern crate flate2; + +use std::io::{Read, Write}; + +use flate2::write::GzEncoder; +use flate2::read::GzDecoder; + +#[test] +fn smoke() { + let mut w = GzEncoder::new(Vec::new(), flate2::Compression::Default); + w.flush().unwrap(); + w.write(b"hello").unwrap(); + + let bytes = w.finish().unwrap(); + + let mut r = GzDecoder::new(&bytes[..]).unwrap(); + let mut s = String::new(); + r.read_to_string(&mut s).unwrap(); + assert_eq!(s, "hello"); +} diff --git a/flate2-0.2.20/tests/good-file.gz b/flate2-0.2.20/tests/good-file.gz new file mode 100644 index 0000000000000000000000000000000000000000..f968689cce01efba445a1d33eb4a21aabf551981 GIT binary patch literal 6766 zcmV-!8j4BrBZ80f#~(j`{PFzy`#=8t>(`(E{Q2we|MR%S-so-X+CFp76$KCKQf!GXY>F2 zD7LX!-%n+!rR~wD@zCr~WwE8M?%wpBUG!87Q!T|XS<_Q2xD>Z;T}vLL+EaVj%xht?Phd?WN4ohCb7(_4d@2#?goIcInlhx?iJLZM1G5 z^J(Qi8ArT|KdpW?9dlhe?WeVCTzmc0ID}^RlT)9sKDKVCzs6}gVO@#tpp9$X+G8E2 z18aVbUi_!(AA0g^NS~TI+S*%fPdgjhzN^bzID8*cO6xo zx;mTTqqCLC8rph{<+tiuDI4I%L_VhS*YimrGY07zf z9D4QbT^7aD)APhvuS0j&w$<{CJn>#O5xB}&&&VUMdlO-prgYke6?>XI%H`4K&cNJ>&HrnOxD##XsYQLme(Z+gAEB zZaCD{aDBPk<2M|1DY|rhV?2K2q3)&YnhMLu&xZ6wBOcszhn^b}J}rSk9XgH2b3by? zBJhx7O}(7k(PApL&Mmp8Pmb2Z>lKJT6Hs&m`1j-&Vk`1ti!kWIDo=3Qx<;NdZDYnZ zsQM9n5<0s9Q3xHJ zQs2A*QKn8?S6r58?v04G46hLMiAu`Z(;h<5aKsHIwgbo>A831Gw1ddjbe^>hNUQV{ z0JFm|I@l@Wxge2g14;$KwRpmE34)L-v!sM7mk$EDf?3&;vBh@aGL)^0P6q?_6bZVr z8l)`@Sc~O(t1{I9P#qwf(@DsbDBHs45f(C8K=BZG>aMhKnR=M|273h9I+fsTy%=zW z3XsVY`8&Qe%VH5p52M22iduxjItaZ1+Q~z48S+7efoyy0Tgla?YghpJmb2F6YGI0) z35?cJ9Hw4Eb^TYx2Qum~wGga78gIj*(0PKnSIE6e)&mPAG+EShPR zm#ar*#X7OVv#)mvQ~0qaVwd%GuVE{MN=4CFxz^cHDvcwuH)MeJMRYWtePd>f5{Nyv zuEy+IxAv>};6&|>8euH4Fso!yhM;lZww_On)0usr&*i|JqWYd1N&R}x|K@Fj0(j&6Pjs~=g39k)8moqNBR&VN> zg3)!|-Pm7`7)Vanae?N-3oR~4UF+t41c8gE!qr3)x&|Ep4iltaB{)PWz%k-;C&r_E zz%iM|5#kPt@kyCNic5$Nw8w5bqagJPV8G~;XirLCgT14r7jO2TqoxHA3J(EqO+p6{ zwd^(r5tV!{hvh~jfY7YtP@qAm2psJy>0I&MU;qb<>tS=LYUu@>mOwsiE~JpiMpxtX zhs~ST&E7g5aL8P{^UWFbg4nhf%y&o@T{PC~SPCJ~yyFA@;<5Z>01*Ki$Li`n6fVHJ~#^16Xg+NO9pl zi|@{}H|H4fDXFA7`>WAJua4lr(`If>KWe&W1tHEb{X_>*q^lwi$!(1(-qdpqVy^SO zDq=_;C=UtV7v^YrpuFR{$^7!OAqW++O0U#I{UVm?A;`7Dl@2H2ifl(1*5H1mJv7ud zkrv!9)B&F4)=TSHiOh~D<`8+2Ef_q_eT{f=h6$NMc2!u#$`?aS3jSF{NOwI`@KWQV zck;>xX0--s(;BP~`^ewK5}l{wDjXpv{1#y7V@df6DlMPIU`pvS#g}0E0KO03FX_c# z4d*lt-wV@I>o-W^@I9DbP*KXZWK8F(xH!=_^s%#~w*92Q2Fi8)0nczzaWi!$wHDfvC>2H*7pmTF14XR&Ll#goYe@ zVLf3pcd4OyTru9tei3~Jhm!=f`lg09z)?|)R!~oNxH@|T7nOmYti33>KzSwovROj9 z5^*wB{a4vCLFD8jTnyVtNS|Ccd8!U7^LDw4^gf^-w%E>AG_q_QU$zvK_8}6_q_7MZ|JB)0iel1T;&GZ zXv=JIy5l~$cT4hD=BBI=5bpeBtlx16l#OUwww0j1_`!${$)IBQYXpphRAA%>>FB~TFDU6wZrw=T$YB0(6Ak< z*Y1`>fE%}F88E1VmE4repX<>Ci@K(Z`AY_&bYX@?k}V(iwR8UX!?9Hy+zzv zKD%B_A0beLNHXTmjLH}QzNM?%$?nI3-(~Cs=y>l6ttqq=cD79L<$R6h*NBA_16s~9 zV12~9DF#N1_#iZ8OP6z^NLW>$7E(a}aSc+2O{9hrkPpXiipu%T1m{hGLfi#V?lPN1g z0;ysl)U}`FeIZ3xU~-;3mqJDW*AefIHy+N{m8?+e@-rFti|PUOx;MGUVf+Tz1gaCf zhwv+Qve!;|^yB-4YArz@ou5di3Z~fNa_0xiVpatY!8xyYDMJC&ji0)ZoKR8Zu(IB` z8D3MS^X!cq=g1Z2Mpf^|jfWVRsO+|G;LI8!A}W=&UQj0#264CA3+ZEoNEcPM_2!mx zZYqt4@3#62=_4vB%Kx7BCjXKkL=4G#%j{o%xT#%Q_|H0JFl$jb!8cNXyqdPs1@ zZSS}4GPx?lRrXQ*2G1J#U<>+Jmy0kT9+h)T>X#bbP`ob09!uiaVN-yV z7f3c)(taNj&}bd<087@_;}cJuLr7=I`C7Y<7eJ?Ynv9Q_3Y8A_+2MQPzLn4+g%2Jr zDS=6(31M8uBV&Y3;jc({J7f=EdC2t2Z|@h8o#E9aTph?y*uQZTeXRp=PPsfBbl?dSrU(keh*MZCUaZL{y!sXg6 z*pJCBVfQ8Lej#1p2Iv*7_O00O9k~;{s&$>3eG~%lTxDr8wu9(O83RY-eLLYX`61y0 z51zX!QBi3qQ_DI4m6;iZ?M~S|fo+N=0r|l>y+XiI=dvw+BVA7ZLY<}1r3oFN7^ifk zm9V^!0rX{}B1uAQmcYC>gyF)^$3g}e)hG~s;2a?Ww5x$vHrU=m0_a731w@}tR+%g_GsW1++%_cEeT= zqytn4b#aRw%I^@8JakdvvBUU+(vd+(d*LPgy|Z?zQ|0|z?b|FwA) z(0=_(AXOuc;k#dUIVZY@GK=+#$+!WzY}2oeFLWrF)Ezf7zU)%61DqOii1B5Yi-L5N z|80Ds(=B^NSkK<3_%5#3I-1<7XKYUL5*-HZ}DHNTp+V9 zL`yi;f9liW%nf2W)d1=REDN%h(NB0#InfYR>oB4>I>mAQu)Z>2r=7kjTJ=NvVsUD_LiNtC_(An< ziRyHA59e2Iydito?nn89dbb31eDq5%bsXZI)`{HJX#Mxo}iZUP;N}Uh9(+6vn)an!K(P>%%#z76L zpZdS_BTBv?vl5`B6#%3CI#Pbv!qufL>`akg^F3%WC-w4#Y|OsmIJ{?!^K0 zGqw_adMd&)rR>kHrLbFH3I!lYpJ4icIeRwm%h=JPM2Gbxe+9*&GBO!(IqmzN<01j+ zJ$b)JKQZbotSn<)%f^)^a;+!lD}GSWqA8h@@GBDzf#^iRp?lX>=x&A%>4)t_Pf#Ys z7oM~i(Kq>~s8NePTrYV^{ZsBb7(;lwFG^oYSZPo`{dVz3u@23=CG%A781#X;DfKo9s zn+ilceV*IOCan%#o6Smqa{3Zo((ta-0ytO9vn)(01q2tQ1C=UU&j!B^eMKn;q|6S# z*Jw9uCE7^{0cn%Sd33v&0-HsjG!R@@_w!j^BtX;oGYT*& z5g!78`a{+Yl^pae^^X;Jw~+}wOa0=!l-n#dnco?sX@I(88wu+2_l<39mnYR1_HU+J zv^Ux23+kI>bRz)!p?s>rDB>m2^Yp{`R9}d3U##X3KGheCIWC;}H@=VIm6#sr`?r!G z^~nmf?5`vfwHG{jfAv1Pj>Ht!3&`eCd@(%ccKa399x}Z!pmXC!{@w$kwAK9^*D$~m zK=#%Do$?QOFF)K2gK^Wb6yqJ?PBS5N25YUmdfE;N6DAqkA%K??~rxi7I zY&~I}`bdEKNHL%jjc!#mMaNMC68k%<>;k8ejsGGzL*#GnDI5Q^GH8_MlB1KUTiCfb z=Ij!jm1Nh`niwO;5T~QwH$9>eLO`Y!@&>OA6~L_HUNM=-d!hOzq@$z`zKtyOOH4%l zMVoy_R{BenFqnPO`6Ty8Yr4jqi&me^Z$`ZgP;aa?rOc$GZc;M(+F|{rnygh1>-mu=dkun`I`J&a{27punmq@o% z)_0g;#z2iTP%}>bUv3mmCryO$3?A0O2t8WHARPmpVWc5uO@C162db>BmyeJvD}sDwJ;s?8fJJ#RCuEF)B1HnUwo>zppkqG7Y<2Upfbk;goepGC#RdjcPeQpUkgRXE8#+tg>v$ zkfM^2vovz0eWpZbj5>M@%pT5nvO0GE599oJ&PwzxZ7{X zU-(M7LA=bf^ICfp4&?M+ZrGG;s!Uy@m;G5ADJP{WzfFK%f>@M+=*MmoV2vorNc%qi z_5c`=?J>{DlV_aQM*y`nCm%ht`f-d*5lU!yeFu7_qEPDcR2k1*Idgs5kpjuH6hMWF z)|i3@TVflN%`1i%wV|U1Zn>J4KDfgi*!i{51ZfX4RM$^^gLMaEUR6$wPt7 zO6G$aX?=MJ0VRel`yHYT4;dg+l=bQiQ>cFT9pj9Hq300&G3z&#V?Umi{!ycEuJGX7 zM~E$_Nvd??@#K9uz7GrOu3g)ihnqE!U+P}A)G`nr~JGKvJcIDQ-c)@e95=As|J z9e=D9jmURz$KU#hF)%7(emnlCs2TI4SZ~yL3#Hz;tK0Dx{6*R-7?<@%jmLL= zKq+>i)9Dl%{4@Y)A(1!_rd<8h|D_|Nw#dYxj3>Qh3X#PKH>f|vJ9N&xmOkGusz9`OQi`~$iCmD%JQcoG6z$Yx?k3)Q% zA##`!RVDuzSt{>6I;G019v}N)dUQ$|{B_TQOt_>V9ZQP-PP|CVnvOL1pE&{UpT9JD zJRAOk6#!4{rmrXUuMV~%qJgl}@u%O~qlCijz9*zd$toe;ll7%R(D;+dSogz@7JtN` zJd$61$46(>>`}RX_}=*gk(g#At`6PXh}2N2IDa7Usu&NSxA@`1^#b?eQA*|S2Hsx3 z6bvNY5@v3*U%$YFJ=HW>uZk&@l_f$pzjcFVEs#$M2wzyAwMMZ}$8nqeO4>q$H1Pa3 z`(^c^s*Vf%QW+IJJKDKc%eT154YHuFCSG3S8Y}?{D<^lD^c&TK1;mK1 io::Result>{ + let mut v = Vec::new(); + let f = try!(File::open(path_compressed)); + try!(try!(GzDecoder::new(f)).read_to_end(&mut v)); + Ok(v) +} + +// Tries to extract path into memory (decompressing all members in case +// of a multi member .gz file). +fn extract_file_multi(path_compressed: &Path) -> io::Result>{ + let mut v = Vec::new(); + let f = try!(File::open(path_compressed)); + try!(try!(MultiGzDecoder::new(f)).read_to_end(&mut v)); + Ok(v) +} diff --git a/flate2-0.2.20/tests/multi.gz b/flate2-0.2.20/tests/multi.gz new file mode 100644 index 0000000000000000000000000000000000000000..cabc89630fe00d6a611e16fdad958ecfd479cd8d GIT binary patch literal 53 zcmb2|=3qED)ij)e+55DPmfk}q2CdCr$JrPd803L6C%`h=e!l0().take(1024 * 1024).collect::>(); + let mut core = Core::new().unwrap(); + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + let v2 = v.clone(); + let t = thread::spawn(move || { + let a = listener.accept().unwrap().0; + let b = a.try_clone().unwrap(); + + let mut v3 = v2.clone(); + let t = thread::spawn(move || { + let mut b = read::DeflateDecoder::new(b); + let mut buf = [0; 1024]; + while v3.len() > 0 { + let n = b.read(&mut buf).unwrap(); + for (actual, expected) in buf[..n].iter().zip(&v3) { + assert_eq!(*actual, *expected); + } + v3.drain(..n); + } + + assert_eq!(b.read(&mut buf).unwrap(), 0); + }); + + let mut a = write::ZlibEncoder::new(a, Compression::Default); + a.write_all(&v2).unwrap(); + a.finish().unwrap() + .shutdown(Shutdown::Write).unwrap(); + + t.join().unwrap(); + }); + + let handle = core.handle(); + let stream = TcpStream::connect(&addr, &handle); + let copy = stream.and_then(|s| { + let (a, b) = s.split(); + let a = read::ZlibDecoder::new(a); + let b = write::DeflateEncoder::new(b, Compression::Default); + copy(a, b) + }).then(|result| { + let (amt, _a, b) = result.unwrap(); + assert_eq!(amt, v.len() as u64); + shutdown(b).map(|_| ()) + }); + + core.run(copy).unwrap(); + t.join().unwrap(); +} diff --git a/flate2-0.2.20/tests/zero-write.rs b/flate2-0.2.20/tests/zero-write.rs new file mode 100644 index 000000000..8174e0c39 --- /dev/null +++ b/flate2-0.2.20/tests/zero-write.rs @@ -0,0 +1,8 @@ +extern crate flate2; + +#[test] +fn zero_write_is_error() { + let mut buf = [0u8]; + let writer = flate2::write::DeflateEncoder::new(&mut buf[..], flate2::Compression::Default); + assert!(writer.finish().is_err()); +} diff --git a/fnv-1.0.6/.cargo-checksum.json b/fnv-1.0.6/.cargo-checksum.json new file mode 100644 index 000000000..19ad74848 --- /dev/null +++ b/fnv-1.0.6/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"} \ No newline at end of file diff --git a/fnv-1.0.6/.travis.yml b/fnv-1.0.6/.travis.yml new file mode 100644 index 000000000..9c58f03c6 --- /dev/null +++ b/fnv-1.0.6/.travis.yml @@ -0,0 +1,8 @@ +language: rust +rust: + - nightly + - beta + - stable + +notifications: + webhooks: http://build.servo.org:54856/travis diff --git a/fnv-1.0.6/Cargo.toml b/fnv-1.0.6/Cargo.toml new file mode 100644 index 000000000..115779985 --- /dev/null +++ b/fnv-1.0.6/Cargo.toml @@ -0,0 +1,25 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "fnv" +version = "1.0.6" +authors = ["Alex Crichton "] +description = "Fowler–Noll–Vo hash function" +documentation = "https://doc.servo.org/fnv/" +readme = "README.md" +license = "Apache-2.0 / MIT" +repository = "https://github.com/servo/rust-fnv" + +[lib] +name = "fnv" +path = "lib.rs" diff --git a/fnv-1.0.6/LICENSE-APACHE b/fnv-1.0.6/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/fnv-1.0.6/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/fnv-1.0.6/LICENSE-MIT b/fnv-1.0.6/LICENSE-MIT new file mode 100644 index 000000000..bc976a272 --- /dev/null +++ b/fnv-1.0.6/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 Contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/fnv-1.0.6/README.md b/fnv-1.0.6/README.md new file mode 100644 index 000000000..6a4c4aeeb --- /dev/null +++ b/fnv-1.0.6/README.md @@ -0,0 +1,81 @@ +# rust-fnv + +An implementation of the [Fowler–Noll–Vo hash function][chongo]. + +### [Read the documentation](https://doc.servo.org/fnv/) + + +## About + +The FNV hash function is a custom `Hasher` implementation that is more +efficient for smaller hash keys. + +[The Rust FAQ states that][faq] while the default `Hasher` implementation, +SipHash, is good in many cases, it is notably slower than other algorithms +with short keys, such as when you have a map of integers to other values. +In cases like these, [FNV is demonstrably faster][graphs]. + +Its disadvantages are that it performs badly on larger inputs, and +provides no protection against collision attacks, where a malicious user +can craft specific keys designed to slow a hasher down. Thus, it is +important to profile your program to ensure that you are using small hash +keys, and be certain that your program could not be exposed to malicious +inputs (including being a networked server). + +The Rust compiler itself uses FNV, as it is not worried about +denial-of-service attacks, and can assume that its inputs are going to be +small—a perfect use case for FNV. + + +## Usage + +To include this crate in your program, add the following to your `Cargo.toml`: + +```toml +[dependencies] +fnv = "1.0.3" +``` + + +## Using FNV in a HashMap + +The `FnvHashMap` type alias is the easiest way to use the standard library’s +`HashMap` with FNV. + +```rust +use fnv::FnvHashMap; + +let mut map = FnvHashMap::default(); +map.insert(1, "one"); +map.insert(2, "two"); + +map = FnvHashMap::with_capacity_and_hasher(10, Default::default()); +map.insert(1, "one"); +map.insert(2, "two"); +``` + +Note, the standard library’s `HashMap::new` and `HashMap::with_capacity` +are only implemented for the `RandomState` hasher, so using `Default` to +get the hasher is the next best option. + + +## Using FNV in a HashSet + +Similarly, `FnvHashSet` is a type alias for the standard library’s `HashSet` +with FNV. + +```rust +use fnv::FnvHashSet; + +let mut set = FnvHashSet::default(); +set.insert(1); +set.insert(2); + +set = FnvHashSet::with_capacity_and_hasher(10, Default::default()); +set.insert(1); +set.insert(2); +``` + +[chongo]: http://www.isthe.com/chongo/tech/comp/fnv/index.html +[faq]: https://www.rust-lang.org/en-US/faq.html#why-are-rusts-hashmaps-slow +[graphs]: http://cglab.ca/~abeinges/blah/hash-rs/ diff --git a/fnv-1.0.6/lib.rs b/fnv-1.0.6/lib.rs new file mode 100644 index 000000000..eaf3d44a3 --- /dev/null +++ b/fnv-1.0.6/lib.rs @@ -0,0 +1,349 @@ +//! An implementation of the [Fowler–Noll–Vo hash function][chongo]. +//! +//! ## About +//! +//! The FNV hash function is a custom `Hasher` implementation that is more +//! efficient for smaller hash keys. +//! +//! [The Rust FAQ states that][faq] while the default `Hasher` implementation, +//! SipHash, is good in many cases, it is notably slower than other algorithms +//! with short keys, such as when you have a map of integers to other values. +//! In cases like these, [FNV is demonstrably faster][graphs]. +//! +//! Its disadvantages are that it performs badly on larger inputs, and +//! provides no protection against collision attacks, where a malicious user +//! can craft specific keys designed to slow a hasher down. Thus, it is +//! important to profile your program to ensure that you are using small hash +//! keys, and be certain that your program could not be exposed to malicious +//! inputs (including being a networked server). +//! +//! The Rust compiler itself uses FNV, as it is not worried about +//! denial-of-service attacks, and can assume that its inputs are going to be +//! small—a perfect use case for FNV. +//! +//! +//! ## Using FNV in a `HashMap` +//! +//! The `FnvHashMap` type alias is the easiest way to use the standard library’s +//! `HashMap` with FNV. +//! +//! ```rust +//! use fnv::FnvHashMap; +//! +//! let mut map = FnvHashMap::default(); +//! map.insert(1, "one"); +//! map.insert(2, "two"); +//! +//! map = FnvHashMap::with_capacity_and_hasher(10, Default::default()); +//! map.insert(1, "one"); +//! map.insert(2, "two"); +//! ``` +//! +//! Note, the standard library’s `HashMap::new` and `HashMap::with_capacity` +//! are only implemented for the `RandomState` hasher, so using `Default` to +//! get the hasher is the next best option. +//! +//! ## Using FNV in a `HashSet` +//! +//! Similarly, `FnvHashSet` is a type alias for the standard library’s `HashSet` +//! with FNV. +//! +//! ```rust +//! use fnv::FnvHashSet; +//! +//! let mut set = FnvHashSet::default(); +//! set.insert(1); +//! set.insert(2); +//! +//! set = FnvHashSet::with_capacity_and_hasher(10, Default::default()); +//! set.insert(1); +//! set.insert(2); +//! ``` +//! +//! [chongo]: http://www.isthe.com/chongo/tech/comp/fnv/index.html +//! [faq]: https://www.rust-lang.org/en-US/faq.html#why-are-rusts-hashmaps-slow +//! [graphs]: http://cglab.ca/~abeinges/blah/hash-rs/ + + +use std::default::Default; +use std::hash::{Hasher, BuildHasherDefault}; +use std::collections::{HashMap, HashSet}; + +/// An implementation of the Fowler–Noll–Vo hash function. +/// +/// See the [crate documentation](index.html) for more details. +#[allow(missing_copy_implementations)] +pub struct FnvHasher(u64); + +impl Default for FnvHasher { + + #[inline] + fn default() -> FnvHasher { + FnvHasher(0xcbf29ce484222325) + } +} + +impl FnvHasher { + /// Create an FNV hasher starting with a state corresponding + /// to the hash `key`. + #[inline] + pub fn with_key(key: u64) -> FnvHasher { + FnvHasher(key) + } +} + +impl Hasher for FnvHasher { + #[inline] + fn finish(&self) -> u64 { + self.0 + } + + #[inline] + fn write(&mut self, bytes: &[u8]) { + let FnvHasher(mut hash) = *self; + + for byte in bytes.iter() { + hash = hash ^ (*byte as u64); + hash = hash.wrapping_mul(0x100000001b3); + } + + *self = FnvHasher(hash); + } +} + +/// A builder for default FNV hashers. +pub type FnvBuildHasher = BuildHasherDefault; + +/// A `HashMap` using a default FNV hasher. +pub type FnvHashMap = HashMap; + +/// A `HashSet` using a default FNV hasher. +pub type FnvHashSet = HashSet; + + +#[cfg(test)] +mod test { + use super::*; + use std::hash::Hasher; + + fn fnv1a(bytes: &[u8]) -> u64 { + let mut hasher = FnvHasher::default(); + hasher.write(bytes); + hasher.finish() + } + + fn repeat_10(bytes: &[u8]) -> Vec { + (0..10).flat_map(|_| bytes.iter().cloned()).collect() + } + + fn repeat_500(bytes: &[u8]) -> Vec { + (0..500).flat_map(|_| bytes.iter().cloned()).collect() + } + + #[test] + fn basic_tests() { + assert_eq!(fnv1a(b""), 0xcbf29ce484222325); + assert_eq!(fnv1a(b"a"), 0xaf63dc4c8601ec8c); + assert_eq!(fnv1a(b"b"), 0xaf63df4c8601f1a5); + assert_eq!(fnv1a(b"c"), 0xaf63de4c8601eff2); + assert_eq!(fnv1a(b"d"), 0xaf63d94c8601e773); + assert_eq!(fnv1a(b"e"), 0xaf63d84c8601e5c0); + assert_eq!(fnv1a(b"f"), 0xaf63db4c8601ead9); + assert_eq!(fnv1a(b"fo"), 0x08985907b541d342); + assert_eq!(fnv1a(b"foo"), 0xdcb27518fed9d577); + assert_eq!(fnv1a(b"foob"), 0xdd120e790c2512af); + assert_eq!(fnv1a(b"fooba"), 0xcac165afa2fef40a); + assert_eq!(fnv1a(b"foobar"), 0x85944171f73967e8); + assert_eq!(fnv1a(b"\0"), 0xaf63bd4c8601b7df); + assert_eq!(fnv1a(b"a\0"), 0x089be207b544f1e4); + assert_eq!(fnv1a(b"b\0"), 0x08a61407b54d9b5f); + assert_eq!(fnv1a(b"c\0"), 0x08a2ae07b54ab836); + assert_eq!(fnv1a(b"d\0"), 0x0891b007b53c4869); + assert_eq!(fnv1a(b"e\0"), 0x088e4a07b5396540); + assert_eq!(fnv1a(b"f\0"), 0x08987c07b5420ebb); + assert_eq!(fnv1a(b"fo\0"), 0xdcb28a18fed9f926); + assert_eq!(fnv1a(b"foo\0"), 0xdd1270790c25b935); + assert_eq!(fnv1a(b"foob\0"), 0xcac146afa2febf5d); + assert_eq!(fnv1a(b"fooba\0"), 0x8593d371f738acfe); + assert_eq!(fnv1a(b"foobar\0"), 0x34531ca7168b8f38); + assert_eq!(fnv1a(b"ch"), 0x08a25607b54a22ae); + assert_eq!(fnv1a(b"cho"), 0xf5faf0190cf90df3); + assert_eq!(fnv1a(b"chon"), 0xf27397910b3221c7); + assert_eq!(fnv1a(b"chong"), 0x2c8c2b76062f22e0); + assert_eq!(fnv1a(b"chongo"), 0xe150688c8217b8fd); + assert_eq!(fnv1a(b"chongo "), 0xf35a83c10e4f1f87); + assert_eq!(fnv1a(b"chongo w"), 0xd1edd10b507344d0); + assert_eq!(fnv1a(b"chongo wa"), 0x2a5ee739b3ddb8c3); + assert_eq!(fnv1a(b"chongo was"), 0xdcfb970ca1c0d310); + assert_eq!(fnv1a(b"chongo was "), 0x4054da76daa6da90); + assert_eq!(fnv1a(b"chongo was h"), 0xf70a2ff589861368); + assert_eq!(fnv1a(b"chongo was he"), 0x4c628b38aed25f17); + assert_eq!(fnv1a(b"chongo was her"), 0x9dd1f6510f78189f); + assert_eq!(fnv1a(b"chongo was here"), 0xa3de85bd491270ce); + assert_eq!(fnv1a(b"chongo was here!"), 0x858e2fa32a55e61d); + assert_eq!(fnv1a(b"chongo was here!\n"), 0x46810940eff5f915); + assert_eq!(fnv1a(b"ch\0"), 0xf5fadd190cf8edaa); + assert_eq!(fnv1a(b"cho\0"), 0xf273ed910b32b3e9); + assert_eq!(fnv1a(b"chon\0"), 0x2c8c5276062f6525); + assert_eq!(fnv1a(b"chong\0"), 0xe150b98c821842a0); + assert_eq!(fnv1a(b"chongo\0"), 0xf35aa3c10e4f55e7); + assert_eq!(fnv1a(b"chongo \0"), 0xd1ed680b50729265); + assert_eq!(fnv1a(b"chongo w\0"), 0x2a5f0639b3dded70); + assert_eq!(fnv1a(b"chongo wa\0"), 0xdcfbaa0ca1c0f359); + assert_eq!(fnv1a(b"chongo was\0"), 0x4054ba76daa6a430); + assert_eq!(fnv1a(b"chongo was \0"), 0xf709c7f5898562b0); + assert_eq!(fnv1a(b"chongo was h\0"), 0x4c62e638aed2f9b8); + assert_eq!(fnv1a(b"chongo was he\0"), 0x9dd1a8510f779415); + assert_eq!(fnv1a(b"chongo was her\0"), 0xa3de2abd4911d62d); + assert_eq!(fnv1a(b"chongo was here\0"), 0x858e0ea32a55ae0a); + assert_eq!(fnv1a(b"chongo was here!\0"), 0x46810f40eff60347); + assert_eq!(fnv1a(b"chongo was here!\n\0"), 0xc33bce57bef63eaf); + assert_eq!(fnv1a(b"cu"), 0x08a24307b54a0265); + assert_eq!(fnv1a(b"cur"), 0xf5b9fd190cc18d15); + assert_eq!(fnv1a(b"curd"), 0x4c968290ace35703); + assert_eq!(fnv1a(b"curds"), 0x07174bd5c64d9350); + assert_eq!(fnv1a(b"curds "), 0x5a294c3ff5d18750); + assert_eq!(fnv1a(b"curds a"), 0x05b3c1aeb308b843); + assert_eq!(fnv1a(b"curds an"), 0xb92a48da37d0f477); + assert_eq!(fnv1a(b"curds and"), 0x73cdddccd80ebc49); + assert_eq!(fnv1a(b"curds and "), 0xd58c4c13210a266b); + assert_eq!(fnv1a(b"curds and w"), 0xe78b6081243ec194); + assert_eq!(fnv1a(b"curds and wh"), 0xb096f77096a39f34); + assert_eq!(fnv1a(b"curds and whe"), 0xb425c54ff807b6a3); + assert_eq!(fnv1a(b"curds and whey"), 0x23e520e2751bb46e); + assert_eq!(fnv1a(b"curds and whey\n"), 0x1a0b44ccfe1385ec); + assert_eq!(fnv1a(b"cu\0"), 0xf5ba4b190cc2119f); + assert_eq!(fnv1a(b"cur\0"), 0x4c962690ace2baaf); + assert_eq!(fnv1a(b"curd\0"), 0x0716ded5c64cda19); + assert_eq!(fnv1a(b"curds\0"), 0x5a292c3ff5d150f0); + assert_eq!(fnv1a(b"curds \0"), 0x05b3e0aeb308ecf0); + assert_eq!(fnv1a(b"curds a\0"), 0xb92a5eda37d119d9); + assert_eq!(fnv1a(b"curds an\0"), 0x73ce41ccd80f6635); + assert_eq!(fnv1a(b"curds and\0"), 0xd58c2c132109f00b); + assert_eq!(fnv1a(b"curds and \0"), 0xe78baf81243f47d1); + assert_eq!(fnv1a(b"curds and w\0"), 0xb0968f7096a2ee7c); + assert_eq!(fnv1a(b"curds and wh\0"), 0xb425a84ff807855c); + assert_eq!(fnv1a(b"curds and whe\0"), 0x23e4e9e2751b56f9); + assert_eq!(fnv1a(b"curds and whey\0"), 0x1a0b4eccfe1396ea); + assert_eq!(fnv1a(b"curds and whey\n\0"), 0x54abd453bb2c9004); + assert_eq!(fnv1a(b"hi"), 0x08ba5f07b55ec3da); + assert_eq!(fnv1a(b"hi\0"), 0x337354193006cb6e); + assert_eq!(fnv1a(b"hello"), 0xa430d84680aabd0b); + assert_eq!(fnv1a(b"hello\0"), 0xa9bc8acca21f39b1); + assert_eq!(fnv1a(b"\xff\x00\x00\x01"), 0x6961196491cc682d); + assert_eq!(fnv1a(b"\x01\x00\x00\xff"), 0xad2bb1774799dfe9); + assert_eq!(fnv1a(b"\xff\x00\x00\x02"), 0x6961166491cc6314); + assert_eq!(fnv1a(b"\x02\x00\x00\xff"), 0x8d1bb3904a3b1236); + assert_eq!(fnv1a(b"\xff\x00\x00\x03"), 0x6961176491cc64c7); + assert_eq!(fnv1a(b"\x03\x00\x00\xff"), 0xed205d87f40434c7); + assert_eq!(fnv1a(b"\xff\x00\x00\x04"), 0x6961146491cc5fae); + assert_eq!(fnv1a(b"\x04\x00\x00\xff"), 0xcd3baf5e44f8ad9c); + assert_eq!(fnv1a(b"\x40\x51\x4e\x44"), 0xe3b36596127cd6d8); + assert_eq!(fnv1a(b"\x44\x4e\x51\x40"), 0xf77f1072c8e8a646); + assert_eq!(fnv1a(b"\x40\x51\x4e\x4a"), 0xe3b36396127cd372); + assert_eq!(fnv1a(b"\x4a\x4e\x51\x40"), 0x6067dce9932ad458); + assert_eq!(fnv1a(b"\x40\x51\x4e\x54"), 0xe3b37596127cf208); + assert_eq!(fnv1a(b"\x54\x4e\x51\x40"), 0x4b7b10fa9fe83936); + assert_eq!(fnv1a(b"127.0.0.1"), 0xaabafe7104d914be); + assert_eq!(fnv1a(b"127.0.0.1\0"), 0xf4d3180b3cde3eda); + assert_eq!(fnv1a(b"127.0.0.2"), 0xaabafd7104d9130b); + assert_eq!(fnv1a(b"127.0.0.2\0"), 0xf4cfb20b3cdb5bb1); + assert_eq!(fnv1a(b"127.0.0.3"), 0xaabafc7104d91158); + assert_eq!(fnv1a(b"127.0.0.3\0"), 0xf4cc4c0b3cd87888); + assert_eq!(fnv1a(b"64.81.78.68"), 0xe729bac5d2a8d3a7); + assert_eq!(fnv1a(b"64.81.78.68\0"), 0x74bc0524f4dfa4c5); + assert_eq!(fnv1a(b"64.81.78.74"), 0xe72630c5d2a5b352); + assert_eq!(fnv1a(b"64.81.78.74\0"), 0x6b983224ef8fb456); + assert_eq!(fnv1a(b"64.81.78.84"), 0xe73042c5d2ae266d); + assert_eq!(fnv1a(b"64.81.78.84\0"), 0x8527e324fdeb4b37); + assert_eq!(fnv1a(b"feedface"), 0x0a83c86fee952abc); + assert_eq!(fnv1a(b"feedface\0"), 0x7318523267779d74); + assert_eq!(fnv1a(b"feedfacedaffdeed"), 0x3e66d3d56b8caca1); + assert_eq!(fnv1a(b"feedfacedaffdeed\0"), 0x956694a5c0095593); + assert_eq!(fnv1a(b"feedfacedeadbeef"), 0xcac54572bb1a6fc8); + assert_eq!(fnv1a(b"feedfacedeadbeef\0"), 0xa7a4c9f3edebf0d8); + assert_eq!(fnv1a(b"line 1\nline 2\nline 3"), 0x7829851fac17b143); + assert_eq!(fnv1a(b"chongo /\\../\\"), 0x2c8f4c9af81bcf06); + assert_eq!(fnv1a(b"chongo /\\../\\\0"), 0xd34e31539740c732); + assert_eq!(fnv1a(b"chongo (Landon Curt Noll) /\\../\\"), 0x3605a2ac253d2db1); + assert_eq!(fnv1a(b"chongo (Landon Curt Noll) /\\../\\\0"), 0x08c11b8346f4a3c3); + assert_eq!(fnv1a(b"http://antwrp.gsfc.nasa.gov/apod/astropix.html"), 0x6be396289ce8a6da); + assert_eq!(fnv1a(b"http://en.wikipedia.org/wiki/Fowler_Noll_Vo_hash"), 0xd9b957fb7fe794c5); + assert_eq!(fnv1a(b"http://epod.usra.edu/"), 0x05be33da04560a93); + assert_eq!(fnv1a(b"http://exoplanet.eu/"), 0x0957f1577ba9747c); + assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/cam3/"), 0xda2cc3acc24fba57); + assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/cams/HMcam/"), 0x74136f185b29e7f0); + assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/kilauea/update/deformation.html"), 0xb2f2b4590edb93b2); + assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/kilauea/update/images.html"), 0xb3608fce8b86ae04); + assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/kilauea/update/maps.html"), 0x4a3a865079359063); + assert_eq!(fnv1a(b"http://hvo.wr.usgs.gov/volcanowatch/current_issue.html"), 0x5b3a7ef496880a50); + assert_eq!(fnv1a(b"http://neo.jpl.nasa.gov/risk/"), 0x48fae3163854c23b); + assert_eq!(fnv1a(b"http://norvig.com/21-days.html"), 0x07aaa640476e0b9a); + assert_eq!(fnv1a(b"http://primes.utm.edu/curios/home.php"), 0x2f653656383a687d); + assert_eq!(fnv1a(b"http://slashdot.org/"), 0xa1031f8e7599d79c); + assert_eq!(fnv1a(b"http://tux.wr.usgs.gov/Maps/155.25-19.5.html"), 0xa31908178ff92477); + assert_eq!(fnv1a(b"http://volcano.wr.usgs.gov/kilaueastatus.php"), 0x097edf3c14c3fb83); + assert_eq!(fnv1a(b"http://www.avo.alaska.edu/activity/Redoubt.php"), 0xb51ca83feaa0971b); + assert_eq!(fnv1a(b"http://www.dilbert.com/fast/"), 0xdd3c0d96d784f2e9); + assert_eq!(fnv1a(b"http://www.fourmilab.ch/gravitation/orbits/"), 0x86cd26a9ea767d78); + assert_eq!(fnv1a(b"http://www.fpoa.net/"), 0xe6b215ff54a30c18); + assert_eq!(fnv1a(b"http://www.ioccc.org/index.html"), 0xec5b06a1c5531093); + assert_eq!(fnv1a(b"http://www.isthe.com/cgi-bin/number.cgi"), 0x45665a929f9ec5e5); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/bio.html"), 0x8c7609b4a9f10907); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/index.html"), 0x89aac3a491f0d729); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/src/calc/lucas-calc"), 0x32ce6b26e0f4a403); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/astro/venus2004.html"), 0x614ab44e02b53e01); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/astro/vita.html"), 0xfa6472eb6eef3290); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/comp/c/expert.html"), 0x9e5d75eb1948eb6a); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/comp/calc/index.html"), 0xb6d12ad4a8671852); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/comp/fnv/index.html"), 0x88826f56eba07af1); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/math/number/howhigh.html"), 0x44535bf2645bc0fd); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/math/number/number.html"), 0x169388ffc21e3728); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/math/prime/mersenne.html"), 0xf68aac9e396d8224); + assert_eq!(fnv1a(b"http://www.isthe.com/chongo/tech/math/prime/mersenne.html#largest"), 0x8e87d7e7472b3883); + assert_eq!(fnv1a(b"http://www.lavarnd.org/cgi-bin/corpspeak.cgi"), 0x295c26caa8b423de); + assert_eq!(fnv1a(b"http://www.lavarnd.org/cgi-bin/haiku.cgi"), 0x322c814292e72176); + assert_eq!(fnv1a(b"http://www.lavarnd.org/cgi-bin/rand-none.cgi"), 0x8a06550eb8af7268); + assert_eq!(fnv1a(b"http://www.lavarnd.org/cgi-bin/randdist.cgi"), 0xef86d60e661bcf71); + assert_eq!(fnv1a(b"http://www.lavarnd.org/index.html"), 0x9e5426c87f30ee54); + assert_eq!(fnv1a(b"http://www.lavarnd.org/what/nist-test.html"), 0xf1ea8aa826fd047e); + assert_eq!(fnv1a(b"http://www.macosxhints.com/"), 0x0babaf9a642cb769); + assert_eq!(fnv1a(b"http://www.mellis.com/"), 0x4b3341d4068d012e); + assert_eq!(fnv1a(b"http://www.nature.nps.gov/air/webcams/parks/havoso2alert/havoalert.cfm"), 0xd15605cbc30a335c); + assert_eq!(fnv1a(b"http://www.nature.nps.gov/air/webcams/parks/havoso2alert/timelines_24.cfm"), 0x5b21060aed8412e5); + assert_eq!(fnv1a(b"http://www.paulnoll.com/"), 0x45e2cda1ce6f4227); + assert_eq!(fnv1a(b"http://www.pepysdiary.com/"), 0x50ae3745033ad7d4); + assert_eq!(fnv1a(b"http://www.sciencenews.org/index/home/activity/view"), 0xaa4588ced46bf414); + assert_eq!(fnv1a(b"http://www.skyandtelescope.com/"), 0xc1b0056c4a95467e); + assert_eq!(fnv1a(b"http://www.sput.nl/~rob/sirius.html"), 0x56576a71de8b4089); + assert_eq!(fnv1a(b"http://www.systemexperts.com/"), 0xbf20965fa6dc927e); + assert_eq!(fnv1a(b"http://www.tq-international.com/phpBB3/index.php"), 0x569f8383c2040882); + assert_eq!(fnv1a(b"http://www.travelquesttours.com/index.htm"), 0xe1e772fba08feca0); + assert_eq!(fnv1a(b"http://www.wunderground.com/global/stations/89606.html"), 0x4ced94af97138ac4); + assert_eq!(fnv1a(&repeat_10(b"21701")), 0xc4112ffb337a82fb); + assert_eq!(fnv1a(&repeat_10(b"M21701")), 0xd64a4fd41de38b7d); + assert_eq!(fnv1a(&repeat_10(b"2^21701-1")), 0x4cfc32329edebcbb); + assert_eq!(fnv1a(&repeat_10(b"\x54\xc5")), 0x0803564445050395); + assert_eq!(fnv1a(&repeat_10(b"\xc5\x54")), 0xaa1574ecf4642ffd); + assert_eq!(fnv1a(&repeat_10(b"23209")), 0x694bc4e54cc315f9); + assert_eq!(fnv1a(&repeat_10(b"M23209")), 0xa3d7cb273b011721); + assert_eq!(fnv1a(&repeat_10(b"2^23209-1")), 0x577c2f8b6115bfa5); + assert_eq!(fnv1a(&repeat_10(b"\x5a\xa9")), 0xb7ec8c1a769fb4c1); + assert_eq!(fnv1a(&repeat_10(b"\xa9\x5a")), 0x5d5cfce63359ab19); + assert_eq!(fnv1a(&repeat_10(b"391581216093")), 0x33b96c3cd65b5f71); + assert_eq!(fnv1a(&repeat_10(b"391581*2^216093-1")), 0xd845097780602bb9); + assert_eq!(fnv1a(&repeat_10(b"\x05\xf9\x9d\x03\x4c\x81")), 0x84d47645d02da3d5); + assert_eq!(fnv1a(&repeat_10(b"FEDCBA9876543210")), 0x83544f33b58773a5); + assert_eq!(fnv1a(&repeat_10(b"\xfe\xdc\xba\x98\x76\x54\x32\x10")), 0x9175cbb2160836c5); + assert_eq!(fnv1a(&repeat_10(b"EFCDAB8967452301")), 0xc71b3bc175e72bc5); + assert_eq!(fnv1a(&repeat_10(b"\xef\xcd\xab\x89\x67\x45\x23\x01")), 0x636806ac222ec985); + assert_eq!(fnv1a(&repeat_10(b"0123456789ABCDEF")), 0xb6ef0e6950f52ed5); + assert_eq!(fnv1a(&repeat_10(b"\x01\x23\x45\x67\x89\xab\xcd\xef")), 0xead3d8a0f3dfdaa5); + assert_eq!(fnv1a(&repeat_10(b"1032547698BADCFE")), 0x922908fe9a861ba5); + assert_eq!(fnv1a(&repeat_10(b"\x10\x32\x54\x76\x98\xba\xdc\xfe")), 0x6d4821de275fd5c5); + assert_eq!(fnv1a(&repeat_500(b"\x00")), 0x1fe3fce62bd816b5); + assert_eq!(fnv1a(&repeat_500(b"\x07")), 0xc23e9fccd6f70591); + assert_eq!(fnv1a(&repeat_500(b"~")), 0xc1af12bdfe16b5b5); + assert_eq!(fnv1a(&repeat_500(b"\x7f")), 0x39e9f18f2f85e221); + } +} diff --git a/foreign-types-0.3.2/.cargo-checksum.json b/foreign-types-0.3.2/.cargo-checksum.json new file mode 100644 index 000000000..4ba7de062 --- /dev/null +++ b/foreign-types-0.3.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"} \ No newline at end of file diff --git a/foreign-types-0.3.2/Cargo.toml b/foreign-types-0.3.2/Cargo.toml new file mode 100644 index 000000000..6ff5567de --- /dev/null +++ b/foreign-types-0.3.2/Cargo.toml @@ -0,0 +1,22 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "foreign-types" +version = "0.3.2" +authors = ["Steven Fackler "] +description = "A framework for Rust wrappers over C APIs" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/sfackler/foreign-types" +[dependencies.foreign-types-shared] +version = "0.1" diff --git a/foreign-types-0.3.2/LICENSE-APACHE b/foreign-types-0.3.2/LICENSE-APACHE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/foreign-types-0.3.2/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/foreign-types-0.3.2/LICENSE-MIT b/foreign-types-0.3.2/LICENSE-MIT new file mode 100644 index 000000000..bb76d0146 --- /dev/null +++ b/foreign-types-0.3.2/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2017 The foreign-types Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/foreign-types-0.3.2/README.md b/foreign-types-0.3.2/README.md new file mode 100644 index 000000000..cd15965fa --- /dev/null +++ b/foreign-types-0.3.2/README.md @@ -0,0 +1,23 @@ +# foreign-types + +[![CircleCI](https://circleci.com/gh/sfackler/foreign-types.svg?style=shield)](https://circleci.com/gh/sfackler/foreign-types) + +[Documentation](https://docs.rs/foreign-types) + +A framework for Rust wrappers over C APIs. + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/foreign-types-0.3.2/src/lib.rs b/foreign-types-0.3.2/src/lib.rs new file mode 100644 index 000000000..6ce959207 --- /dev/null +++ b/foreign-types-0.3.2/src/lib.rs @@ -0,0 +1,306 @@ +//! A framework for Rust wrappers over C APIs. +//! +//! Ownership is as important in C as it is in Rust, but the semantics are often implicit. In +//! particular, pointer-to-value is commonly used to pass C values both when transferring ownership +//! or a borrow. +//! +//! This crate provides a framework to define a Rust wrapper over these kinds of raw C APIs in a way +//! that allows ownership semantics to be expressed in an ergonomic manner. The framework takes a +//! dual-type approach similar to APIs in the standard library such as `PathBuf`/`Path` or `String`/ +//! `str`. One type represents an owned value and references to the other represent borrowed +//! values. +//! +//! # Examples +//! +//! ``` +//! use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; +//! use std::ops::{Deref, DerefMut}; +//! +//! mod foo_sys { +//! pub enum FOO {} +//! +//! extern { +//! pub fn FOO_free(foo: *mut FOO); +//! } +//! } +//! +//! // The borrowed type is a newtype wrapper around an `Opaque` value. +//! // +//! // `FooRef` values never exist; we instead create references to `FooRef`s +//! // from raw C pointers. +//! pub struct FooRef(Opaque); +//! +//! impl ForeignTypeRef for FooRef { +//! type CType = foo_sys::FOO; +//! } +//! +//! // The owned type is simply a newtype wrapper around the raw C type. +//! // +//! // It dereferences to `FooRef`, so methods that do not require ownership +//! // should be defined there. +//! pub struct Foo(*mut foo_sys::FOO); +//! +//! impl Drop for Foo { +//! fn drop(&mut self) { +//! unsafe { foo_sys::FOO_free(self.0) } +//! } +//! } +//! +//! impl ForeignType for Foo { +//! type CType = foo_sys::FOO; +//! type Ref = FooRef; +//! +//! unsafe fn from_ptr(ptr: *mut foo_sys::FOO) -> Foo { +//! Foo(ptr) +//! } +//! +//! fn as_ptr(&self) -> *mut foo_sys::FOO { +//! self.0 +//! } +//! } +//! +//! impl Deref for Foo { +//! type Target = FooRef; +//! +//! fn deref(&self) -> &FooRef { +//! unsafe { FooRef::from_ptr(self.0) } +//! } +//! } +//! +//! impl DerefMut for Foo { +//! fn deref_mut(&mut self) -> &mut FooRef { +//! unsafe { FooRef::from_ptr_mut(self.0) } +//! } +//! } +//! ``` +//! +//! The `foreign_type!` macro can generate this boilerplate for you: +//! +//! ``` +//! #[macro_use] +//! extern crate foreign_types; +//! +//! mod foo_sys { +//! pub enum FOO {} +//! +//! extern { +//! pub fn FOO_free(foo: *mut FOO); +//! pub fn FOO_duplicate(foo: *mut FOO) -> *mut FOO; // Optional +//! } +//! } +//! +//! foreign_type! { +//! type CType = foo_sys::FOO; +//! fn drop = foo_sys::FOO_free; +//! fn clone = foo_sys::FOO_duplicate; // Optional +//! /// A Foo. +//! pub struct Foo; +//! /// A borrowed Foo. +//! pub struct FooRef; +//! } +//! +//! # fn main() {} +//! ``` +//! +//! If `fn clone` is specified, then it must take `CType` as an argument and return a copy of it as `CType`. +//! It will be used to implement `ToOwned` and `Clone`. +//! +//! `#[derive(…)] is permitted before the lines with `pub struct`. +//! `#[doc(hidden)]` before the `type CType` line will hide the `foreign_type!` implementations from documentation. +//! +//! Say we then have a separate type in our C API that contains a `FOO`: +//! +//! ``` +//! mod foo_sys { +//! pub enum FOO {} +//! pub enum BAR {} +//! +//! extern { +//! pub fn FOO_free(foo: *mut FOO); +//! pub fn BAR_free(bar: *mut BAR); +//! pub fn BAR_get_foo(bar: *mut BAR) -> *mut FOO; +//! } +//! } +//! ``` +//! +//! The documentation for the C library states that `BAR_get_foo` returns a reference into the `BAR` +//! passed to it, which translates into a reference in Rust. It also says that we're allowed to +//! modify the `FOO`, so we'll define a pair of accessor methods, one immutable and one mutable: +//! +//! ``` +//! #[macro_use] +//! extern crate foreign_types; +//! +//! use foreign_types::ForeignTypeRef; +//! +//! mod foo_sys { +//! pub enum FOO {} +//! pub enum BAR {} +//! +//! extern { +//! pub fn FOO_free(foo: *mut FOO); +//! pub fn BAR_free(bar: *mut BAR); +//! pub fn BAR_get_foo(bar: *mut BAR) -> *mut FOO; +//! } +//! } +//! +//! foreign_type! { +//! #[doc(hidden)] +//! type CType = foo_sys::FOO; +//! fn drop = foo_sys::FOO_free; +//! /// A Foo. +//! pub struct Foo; +//! /// A borrowed Foo. +//! pub struct FooRef; +//! } +//! +//! foreign_type! { +//! type CType = foo_sys::BAR; +//! fn drop = foo_sys::BAR_free; +//! /// A Foo. +//! pub struct Bar; +//! /// A borrowed Bar. +//! pub struct BarRef; +//! } +//! +//! impl BarRef { +//! fn foo(&self) -> &FooRef { +//! unsafe { FooRef::from_ptr(foo_sys::BAR_get_foo(self.as_ptr())) } +//! } +//! +//! fn foo_mut(&mut self) -> &mut FooRef { +//! unsafe { FooRef::from_ptr_mut(foo_sys::BAR_get_foo(self.as_ptr())) } +//! } +//! } +//! +//! # fn main() {} +//! ``` +#![no_std] +#![warn(missing_docs)] +#![doc(html_root_url="https://docs.rs/foreign-types/0.3")] +extern crate foreign_types_shared; + +#[doc(inline)] +pub use foreign_types_shared::*; + +/// A macro to easily define wrappers for foreign types. +/// +/// # Examples +/// +/// ``` +/// #[macro_use] +/// extern crate foreign_types; +/// +/// # mod openssl_sys { pub type SSL = (); pub unsafe fn SSL_free(_: *mut SSL) {} pub unsafe fn SSL_dup(x: *mut SSL) -> *mut SSL {x} } +/// foreign_type! { +/// type CType = openssl_sys::SSL; +/// fn drop = openssl_sys::SSL_free; +/// fn clone = openssl_sys::SSL_dup; +/// /// Documentation for the owned type. +/// pub struct Ssl; +/// /// Documentation for the borrowed type. +/// pub struct SslRef; +/// } +/// +/// # fn main() {} +/// ``` +#[macro_export] +macro_rules! foreign_type { + ( + $(#[$impl_attr:meta])* + type CType = $ctype:ty; + fn drop = $drop:expr; + $(fn clone = $clone:expr;)* + $(#[$owned_attr:meta])* + pub struct $owned:ident; + $(#[$borrowed_attr:meta])* + pub struct $borrowed:ident; + ) => { + $(#[$owned_attr])* + pub struct $owned(*mut $ctype); + + $(#[$impl_attr])* + impl $crate::ForeignType for $owned { + type CType = $ctype; + type Ref = $borrowed; + + #[inline] + unsafe fn from_ptr(ptr: *mut $ctype) -> $owned { + $owned(ptr) + } + + #[inline] + fn as_ptr(&self) -> *mut $ctype { + self.0 + } + } + + impl Drop for $owned { + #[inline] + fn drop(&mut self) { + unsafe { $drop(self.0) } + } + } + + $( + impl Clone for $owned { + #[inline] + fn clone(&self) -> $owned { + unsafe { + let handle: *mut $ctype = $clone(self.0); + $crate::ForeignType::from_ptr(handle) + } + } + } + + impl ::std::borrow::ToOwned for $borrowed { + type Owned = $owned; + #[inline] + fn to_owned(&self) -> $owned { + unsafe { + let handle: *mut $ctype = $clone($crate::ForeignTypeRef::as_ptr(self)); + $crate::ForeignType::from_ptr(handle) + } + } + } + )* + + impl ::std::ops::Deref for $owned { + type Target = $borrowed; + + #[inline] + fn deref(&self) -> &$borrowed { + unsafe { $crate::ForeignTypeRef::from_ptr(self.0) } + } + } + + impl ::std::ops::DerefMut for $owned { + #[inline] + fn deref_mut(&mut self) -> &mut $borrowed { + unsafe { $crate::ForeignTypeRef::from_ptr_mut(self.0) } + } + } + + impl ::std::borrow::Borrow<$borrowed> for $owned { + #[inline] + fn borrow(&self) -> &$borrowed { + &**self + } + } + + impl ::std::convert::AsRef<$borrowed> for $owned { + #[inline] + fn as_ref(&self) -> &$borrowed { + &**self + } + } + + $(#[$borrowed_attr])* + pub struct $borrowed($crate::Opaque); + + $(#[$impl_attr])* + impl $crate::ForeignTypeRef for $borrowed { + type CType = $ctype; + } + } +} diff --git a/foreign-types-shared-0.1.1/.cargo-checksum.json b/foreign-types-shared-0.1.1/.cargo-checksum.json new file mode 100644 index 000000000..5fc4da45f --- /dev/null +++ b/foreign-types-shared-0.1.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"} \ No newline at end of file diff --git a/foreign-types-shared-0.1.1/Cargo.toml b/foreign-types-shared-0.1.1/Cargo.toml new file mode 100644 index 000000000..e2cb783b9 --- /dev/null +++ b/foreign-types-shared-0.1.1/Cargo.toml @@ -0,0 +1,21 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "foreign-types-shared" +version = "0.1.1" +authors = ["Steven Fackler "] +description = "An internal crate used by foreign-types" +license = "MIT/Apache-2.0" +repository = "https://github.com/sfackler/foreign-types" + +[dependencies] diff --git a/foreign-types-shared-0.1.1/LICENSE-APACHE b/foreign-types-shared-0.1.1/LICENSE-APACHE new file mode 100644 index 000000000..8f71f43fe --- /dev/null +++ b/foreign-types-shared-0.1.1/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/foreign-types-shared-0.1.1/LICENSE-MIT b/foreign-types-shared-0.1.1/LICENSE-MIT new file mode 100644 index 000000000..bb76d0146 --- /dev/null +++ b/foreign-types-shared-0.1.1/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2017 The foreign-types Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/foreign-types-shared-0.1.1/src/lib.rs b/foreign-types-shared-0.1.1/src/lib.rs new file mode 100644 index 000000000..cbebc3353 --- /dev/null +++ b/foreign-types-shared-0.1.1/src/lib.rs @@ -0,0 +1,51 @@ +//! Internal crate used by foreign-types + +#![no_std] +#![warn(missing_docs)] +#![doc(html_root_url="https://docs.rs/foreign-types-shared/0.1")] + +use core::cell::UnsafeCell; + +/// An opaque type used to define `ForeignTypeRef` types. +/// +/// A type implementing `ForeignTypeRef` should simply be a newtype wrapper around this type. +pub struct Opaque(UnsafeCell<()>); + +/// A type implemented by wrappers over foreign types. +pub trait ForeignType: Sized { + /// The raw C type. + type CType; + + /// The type representing a reference to this type. + type Ref: ForeignTypeRef; + + /// Constructs an instance of this type from its raw type. + unsafe fn from_ptr(ptr: *mut Self::CType) -> Self; + + /// Returns a raw pointer to the wrapped value. + fn as_ptr(&self) -> *mut Self::CType; +} + +/// A trait implemented by types which reference borrowed foreign types. +pub trait ForeignTypeRef: Sized { + /// The raw C type. + type CType; + + /// Constructs a shared instance of this type from its raw type. + #[inline] + unsafe fn from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self { + &*(ptr as *mut _) + } + + /// Constructs a mutable reference of this type from its raw type. + #[inline] + unsafe fn from_ptr_mut<'a>(ptr: *mut Self::CType) -> &'a mut Self { + &mut *(ptr as *mut _) + } + + /// Returns a raw pointer to the wrapped value. + #[inline] + fn as_ptr(&self) -> *mut Self::CType { + self as *const _ as *mut _ + } +} diff --git a/fs2-0.4.3/.appveyor.yml b/fs2-0.4.3/.appveyor.yml new file mode 100644 index 000000000..a54c426af --- /dev/null +++ b/fs2-0.4.3/.appveyor.yml @@ -0,0 +1,18 @@ +environment: + matrix: + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc + - TARGET: x86_64-pc-windows-gnu + - TARGET: i686-pc-windows-gnu + +install: + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" -FileName "rust-nightly.exe" + - ps: .\rust-nightly.exe /VERYSILENT /NORESTART /DIR="C:\rust" | Out-Null + - ps: $env:PATH="$env:PATH;C:\rust\bin" + +build_script: + - cargo build -v + +test_script: + - SET RUST_BACKTRACE=1 + - cargo test -v diff --git a/fs2-0.4.3/.cargo-checksum.json b/fs2-0.4.3/.cargo-checksum.json new file mode 100644 index 000000000..b5f1e1d84 --- /dev/null +++ b/fs2-0.4.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"} \ No newline at end of file diff --git a/fs2-0.4.3/.travis.yml b/fs2-0.4.3/.travis.yml new file mode 100644 index 000000000..3e8a024f9 --- /dev/null +++ b/fs2-0.4.3/.travis.yml @@ -0,0 +1,21 @@ +language: rust + +rust: +- 1.8.0 +- stable +- nightly + +os: + - linux + - osx + +env: + matrix: + - ARCH=x86_64 + - ARCH=i686 + +script: + - cargo build --verbose + - if [[ $TRAVIS_RUST_VERSION = nightly* ]]; then + env RUST_BACKTRACE=1 cargo test -v; + fi diff --git a/fs2-0.4.3/Cargo.toml b/fs2-0.4.3/Cargo.toml new file mode 100644 index 000000000..4c6aded51 --- /dev/null +++ b/fs2-0.4.3/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "fs2" +version = "0.4.3" +authors = ["Dan Burkert "] +description = "Cross-platform file locks and file duplication." +documentation = "https://docs.rs/fs2" +keywords = ["file", "file-system", "lock", "duplicate", "flock"] +license = "MIT/Apache-2.0" +repository = "https://github.com/danburkert/fs2-rs" +[dev-dependencies.tempdir] +version = "0.3" +[target."cfg(unix)".dependencies.libc] +version = "0.2.30" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["handleapi", "processthreadsapi", "winerror", "fileapi", "winbase", "std"] +[badges.appveyor] +repository = "danburkert/fs2-rs" + +[badges.travis-ci] +repository = "danburkert/fs2-rs" diff --git a/fs2-0.4.3/LICENSE-APACHE b/fs2-0.4.3/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/fs2-0.4.3/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/fs2-0.4.3/LICENSE-MIT b/fs2-0.4.3/LICENSE-MIT new file mode 100644 index 000000000..e69282e38 --- /dev/null +++ b/fs2-0.4.3/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/fs2-0.4.3/README.md b/fs2-0.4.3/README.md new file mode 100644 index 000000000..c10459a68 --- /dev/null +++ b/fs2-0.4.3/README.md @@ -0,0 +1,50 @@ +# fs2 + +Extended utilities for working with files and filesystems in Rust. `fs2` +requires Rust stable 1.8 or greater. + +[![Build Status](https://travis-ci.org/danburkert/fs2-rs.svg?branch=master)](https://travis-ci.org/danburkert/fs2-rs) +[![Windows Build status](https://ci.appveyor.com/api/projects/status/iuvjv1aaaml0rntt/branch/master?svg=true)](https://ci.appveyor.com/project/danburkert/fs2-rs/branch/master) +[![Documentation](https://docs.rs/fs2/badge.svg)](https://docs.rs/memmap) +[![Crate](https://img.shields.io/crates/v/fs2.svg)](https://crates.io/crates/memmap) + +## Features + +- [x] file descriptor duplication. +- [x] file locks. +- [x] file (pre)allocation. +- [x] file allocation information. +- [x] filesystem space usage information. + +## Platforms + +`fs2` should work on any platform supported by +[`libc`](https://github.com/rust-lang-nursery/libc#platforms-and-documentation). + +`fs2` is continuously tested on: + * `x86_64-unknown-linux-gnu` (Linux) + * `i686-unknown-linux-gnu` + * `x86_64-apple-darwin` (OSX) + * `i686-apple-darwin` + * `x86_64-pc-windows-msvc` (Windows) + * `i686-pc-windows-msvc` + * `x86_64-pc-windows-gnu` + * `i686-pc-windows-gnu` + +## Benchmarks + +Simple benchmarks are provided for the methods provided. Many of these +benchmarks use files in a temporary directory. On many modern Linux distros the +default temporary directory, `/tmp`, is mounted on a tempfs filesystem, which +will have different performance characteristics than a disk-backed filesystem. +The temporary directory is configurable at runtime through the environment (see +[`env::temp_dir`](https://doc.rust-lang.org/stable/std/env/fn.temp_dir.html)). + +## License + +`fs2` is primarily distributed under the terms of both the MIT license and the +Apache License (Version 2.0). + +See [LICENSE-APACHE](LICENSE-APACHE), [LICENSE-MIT](LICENSE-MIT) for details. + +Copyright (c) 2015 Dan Burkert. diff --git a/fs2-0.4.3/src/lib.rs b/fs2-0.4.3/src/lib.rs new file mode 100644 index 000000000..51b22db6a --- /dev/null +++ b/fs2-0.4.3/src/lib.rs @@ -0,0 +1,458 @@ +//! Extended utilities for working with files and filesystems in Rust. + +#![doc(html_root_url = "https://docs.rs/fs2/0.4.3")] + +#![cfg_attr(test, feature(test))] + +#[cfg(windows)] +extern crate winapi; + +#[cfg(unix)] +mod unix; +#[cfg(unix)] +use unix as sys; + +#[cfg(windows)] +mod windows; +#[cfg(windows)] +use windows as sys; + +use std::fs::File; +use std::io::{Error, Result}; +use std::path::Path; + +/// Extension trait for `std::fs::File` which provides allocation, duplication and locking methods. +/// +/// ## Notes on File Locks +/// +/// This library provides whole-file locks in both shared (read) and exclusive +/// (read-write) varieties. +/// +/// File locks are a cross-platform hazard since the file lock APIs exposed by +/// operating system kernels vary in subtle and not-so-subtle ways. +/// +/// The API exposed by this library can be safely used across platforms as long +/// as the following rules are followed: +/// +/// * Multiple locks should not be created on an individual `File` instance +/// concurrently. +/// * Duplicated files should not be locked without great care. +/// * Files to be locked should be opened with at least read or write +/// permissions. +/// * File locks may only be relied upon to be advisory. +/// +/// See the tests in `lib.rs` for cross-platform lock behavior that may be +/// relied upon; see the tests in `unix.rs` and `windows.rs` for examples of +/// platform-specific behavior. File locks are implemented with +/// [`flock(2)`](http://man7.org/linux/man-pages/man2/flock.2.html) on Unix and +/// [`LockFile`](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365202(v=vs.85).aspx) +/// on Windows. +pub trait FileExt { + + /// Returns a duplicate instance of the file. + /// + /// The returned file will share the same file position as the original + /// file. + /// + /// If using rustc version 1.9 or later, prefer using `File::try_clone` to this. + /// + /// # Notes + /// + /// This is implemented with + /// [`dup(2)`](http://man7.org/linux/man-pages/man2/dup.2.html) on Unix and + /// [`DuplicateHandle`](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724251(v=vs.85).aspx) + /// on Windows. + fn duplicate(&self) -> Result; + + /// Returns the amount of physical space allocated for a file. + fn allocated_size(&self) -> Result; + + /// Ensures that at least `len` bytes of disk space are allocated for the + /// file, and the file size is at least `len` bytes. After a successful call + /// to `allocate`, subsequent writes to the file within the specified length + /// are guaranteed not to fail because of lack of disk space. + fn allocate(&self, len: u64) -> Result<()>; + + /// Locks the file for shared usage, blocking if the file is currently + /// locked exclusively. + fn lock_shared(&self) -> Result<()>; + + /// Locks the file for exclusive usage, blocking if the file is currently + /// locked. + fn lock_exclusive(&self) -> Result<()>; + + /// Locks the file for shared usage, or returns a an error if the file is + /// currently locked (see `lock_contended_error`). + fn try_lock_shared(&self) -> Result<()>; + + /// Locks the file for shared usage, or returns a an error if the file is + /// currently locked (see `lock_contended_error`). + fn try_lock_exclusive(&self) -> Result<()>; + + /// Unlocks the file. + fn unlock(&self) -> Result<()>; +} + +impl FileExt for File { + fn duplicate(&self) -> Result { + sys::duplicate(self) + } + fn allocated_size(&self) -> Result { + sys::allocated_size(self) + } + fn allocate(&self, len: u64) -> Result<()> { + sys::allocate(self, len) + } + fn lock_shared(&self) -> Result<()> { + sys::lock_shared(self) + } + fn lock_exclusive(&self) -> Result<()> { + sys::lock_exclusive(self) + } + fn try_lock_shared(&self) -> Result<()> { + sys::try_lock_shared(self) + } + fn try_lock_exclusive(&self) -> Result<()> { + sys::try_lock_exclusive(self) + } + fn unlock(&self) -> Result<()> { + sys::unlock(self) + } +} + +/// Returns the error that a call to a try lock method on a contended file will +/// return. +pub fn lock_contended_error() -> Error { + sys::lock_error() +} + +/// `FsStats` contains some common stats about a file system. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct FsStats { + free_space: u64, + available_space: u64, + total_space: u64, + allocation_granularity: u64, +} + +impl FsStats { + /// Returns the number of free bytes in the file system containing the provided + /// path. + pub fn free_space(&self) -> u64 { + self.free_space + } + + /// Returns the available space in bytes to non-priveleged users in the file + /// system containing the provided path. + pub fn available_space(&self) -> u64 { + self.available_space + } + + /// Returns the total space in bytes in the file system containing the provided + /// path. + pub fn total_space(&self) -> u64 { + self.total_space + } + + /// Returns the filesystem's disk space allocation granularity in bytes. + /// The provided path may be for any file in the filesystem. + /// + /// On Posix, this is equivalent to the filesystem's block size. + /// On Windows, this is equivalent to the filesystem's cluster size. + pub fn allocation_granularity(&self) -> u64 { + self.allocation_granularity + } +} + +/// Get the stats of the file system containing the provided path. +pub fn statvfs

(path: P) -> Result where P: AsRef { + sys::statvfs(path.as_ref()) +} + +/// Returns the number of free bytes in the file system containing the provided +/// path. +pub fn free_space

(path: P) -> Result where P: AsRef { + statvfs(path).map(|stat| stat.free_space) +} + +/// Returns the available space in bytes to non-priveleged users in the file +/// system containing the provided path. +pub fn available_space

(path: P) -> Result where P: AsRef { + statvfs(path).map(|stat| stat.available_space) +} + +/// Returns the total space in bytes in the file system containing the provided +/// path. +pub fn total_space

(path: P) -> Result where P: AsRef { + statvfs(path).map(|stat| stat.total_space) +} + +/// Returns the filesystem's disk space allocation granularity in bytes. +/// The provided path may be for any file in the filesystem. +/// +/// On Posix, this is equivalent to the filesystem's block size. +/// On Windows, this is equivalent to the filesystem's cluster size. +pub fn allocation_granularity

(path: P) -> Result where P: AsRef { + statvfs(path).map(|stat| stat.allocation_granularity) +} + +#[cfg(test)] +mod test { + + extern crate tempdir; + extern crate test; + + use std::fs; + use super::*; + use std::io::{Read, Seek, SeekFrom, Write}; + + /// Tests file duplication. + #[test] + fn duplicate() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let mut file1 = + fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let mut file2 = file1.duplicate().unwrap(); + + // Write into the first file and then drop it. + file1.write_all(b"foo").unwrap(); + drop(file1); + + let mut buf = vec![]; + + // Read from the second file; since the position is shared it will already be at EOF. + file2.read_to_end(&mut buf).unwrap(); + assert_eq!(0, buf.len()); + + // Rewind and read. + file2.seek(SeekFrom::Start(0)).unwrap(); + file2.read_to_end(&mut buf).unwrap(); + assert_eq!(&buf, &b"foo"); + } + + /// Tests shared file lock operations. + #[test] + fn lock_shared() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file3 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + // Concurrent shared access is OK, but not shared and exclusive. + file1.lock_shared().unwrap(); + file2.lock_shared().unwrap(); + assert_eq!(file3.try_lock_exclusive().unwrap_err().kind(), + lock_contended_error().kind()); + file1.unlock().unwrap(); + assert_eq!(file3.try_lock_exclusive().unwrap_err().kind(), + lock_contended_error().kind()); + + // Once all shared file locks are dropped, an exclusive lock may be created; + file2.unlock().unwrap(); + file3.lock_exclusive().unwrap(); + } + + /// Tests exclusive file lock operations. + #[test] + fn lock_exclusive() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + // No other access is possible once an exclusive lock is created. + file1.lock_exclusive().unwrap(); + assert_eq!(file2.try_lock_exclusive().unwrap_err().kind(), + lock_contended_error().kind()); + assert_eq!(file2.try_lock_shared().unwrap_err().kind(), + lock_contended_error().kind()); + + // Once the exclusive lock is dropped, the second file is able to create a lock. + file1.unlock().unwrap(); + file2.lock_exclusive().unwrap(); + } + + /// Tests that a lock is released after the file that owns it is dropped. + #[test] + fn lock_cleanup() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + file1.lock_exclusive().unwrap(); + assert_eq!(file2.try_lock_shared().unwrap_err().kind(), + lock_contended_error().kind()); + + // Drop file1; the lock should be released. + drop(file1); + file2.lock_shared().unwrap(); + } + + /// Tests file allocation. + #[test] + fn allocate() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + let blksize = allocation_granularity(&path).unwrap(); + + // New files are created with no allocated size. + assert_eq!(0, file.allocated_size().unwrap()); + assert_eq!(0, file.metadata().unwrap().len()); + + // Allocate space for the file, checking that the allocated size steps + // up by block size, and the file length matches the allocated size. + + file.allocate(2 * blksize - 1).unwrap(); + assert_eq!(2 * blksize, file.allocated_size().unwrap()); + assert_eq!(2 * blksize - 1, file.metadata().unwrap().len()); + + // Truncate the file, checking that the allocated size steps down by + // block size. + + file.set_len(blksize + 1).unwrap(); + assert_eq!(2 * blksize, file.allocated_size().unwrap()); + assert_eq!(blksize + 1, file.metadata().unwrap().len()); + } + + /// Checks filesystem space methods. + #[test] + fn filesystem_space() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let total_space = total_space(&tempdir.path()).unwrap(); + let free_space = free_space(&tempdir.path()).unwrap(); + let available_space = available_space(&tempdir.path()).unwrap(); + + assert!(total_space > free_space); + assert!(total_space > available_space); + assert!(available_space <= free_space); + } + + /// Benchmarks creating and removing a file. This is a baseline benchmark + /// for comparing against the truncate and allocate benchmarks. + #[bench] + fn bench_file_create(b: &mut test::Bencher) { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("file"); + + b.iter(|| { + fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&path) + .unwrap(); + fs::remove_file(&path).unwrap(); + }); + } + + /// Benchmarks creating a file, truncating it to 32MiB, and deleting it. + #[bench] + fn bench_file_truncate(b: &mut test::Bencher) { + let size = 32 * 1024 * 1024; + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("file"); + + b.iter(|| { + let file = fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&path) + .unwrap(); + file.set_len(size).unwrap(); + fs::remove_file(&path).unwrap(); + }); + } + + /// Benchmarks creating a file, allocating 32MiB for it, and deleting it. + #[bench] + fn bench_file_allocate(b: &mut test::Bencher) { + let size = 32 * 1024 * 1024; + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("file"); + + b.iter(|| { + let file = fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&path) + .unwrap(); + file.allocate(size).unwrap(); + fs::remove_file(&path).unwrap(); + }); + } + + /// Benchmarks creating a file, allocating 32MiB for it, and deleting it. + #[bench] + fn bench_allocated_size(b: &mut test::Bencher) { + let size = 32 * 1024 * 1024; + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("file"); + let file = fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&path) + .unwrap(); + file.allocate(size).unwrap(); + + b.iter(|| { + file.allocated_size().unwrap(); + }); + } + + /// Benchmarks duplicating a file descriptor or handle. + #[bench] + fn bench_duplicate(b: &mut test::Bencher) { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + b.iter(|| test::black_box(file.duplicate().unwrap())); + } + + /// Benchmarks locking and unlocking a file lock. + #[bench] + fn bench_lock_unlock(b: &mut test::Bencher) { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + b.iter(|| { + file.lock_exclusive().unwrap(); + file.unlock().unwrap(); + }); + } + + /// Benchmarks the free space method. + #[bench] + fn bench_free_space(b: &mut test::Bencher) { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + b.iter(|| { + test::black_box(free_space(&tempdir.path()).unwrap()); + }); + } + + /// Benchmarks the available space method. + #[bench] + fn bench_available_space(b: &mut test::Bencher) { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + b.iter(|| { + test::black_box(available_space(&tempdir.path()).unwrap()); + }); + } + + /// Benchmarks the total space method. + #[bench] + fn bench_total_space(b: &mut test::Bencher) { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + b.iter(|| { + test::black_box(total_space(&tempdir.path()).unwrap()); + }); + } +} diff --git a/fs2-0.4.3/src/unix.rs b/fs2-0.4.3/src/unix.rs new file mode 100644 index 000000000..91867f7e3 --- /dev/null +++ b/fs2-0.4.3/src/unix.rs @@ -0,0 +1,250 @@ +extern crate libc; + +use std::ffi::CString; +use std::fs::File; +use std::io::{Error, ErrorKind, Result}; +use std::mem; +use std::os::unix::ffi::OsStrExt; +use std::os::unix::fs::MetadataExt; +use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::path::Path; + +use FsStats; + +pub fn duplicate(file: &File) -> Result { + unsafe { + let fd = libc::dup(file.as_raw_fd()); + + if fd < 0 { + Err(Error::last_os_error()) + } else { + Ok(File::from_raw_fd(fd)) + } + } +} + +pub fn lock_shared(file: &File) -> Result<()> { + flock(file, libc::LOCK_SH) +} + +pub fn lock_exclusive(file: &File) -> Result<()> { + flock(file, libc::LOCK_EX) +} + +pub fn try_lock_shared(file: &File) -> Result<()> { + flock(file, libc::LOCK_SH | libc::LOCK_NB) +} + +pub fn try_lock_exclusive(file: &File) -> Result<()> { + flock(file, libc::LOCK_EX | libc::LOCK_NB) +} + +pub fn unlock(file: &File) -> Result<()> { + flock(file, libc::LOCK_UN) +} + +pub fn lock_error() -> Error { + Error::from_raw_os_error(libc::EWOULDBLOCK) +} + +#[cfg(not(target_os = "solaris"))] +fn flock(file: &File, flag: libc::c_int) -> Result<()> { + let ret = unsafe { libc::flock(file.as_raw_fd(), flag) }; + if ret < 0 { Err(Error::last_os_error()) } else { Ok(()) } +} + +/// Simulate flock() using fcntl(); primarily for Oracle Solaris. +#[cfg(target_os = "solaris")] +fn flock(file: &File, flag: libc::c_int) -> Result<()> { + let mut fl = libc::flock { + l_whence: 0, + l_start: 0, + l_len: 0, + l_type: 0, + l_pad: [0; 4], + l_pid: 0, + l_sysid: 0, + }; + + // In non-blocking mode, use F_SETLK for cmd, F_SETLKW otherwise, and don't forget to clear + // LOCK_NB. + let (cmd, operation) = match flag & libc::LOCK_NB { + 0 => (libc::F_SETLKW, flag), + _ => (libc::F_SETLK, flag & !libc::LOCK_NB), + }; + + match operation { + libc::LOCK_SH => fl.l_type |= libc::F_RDLCK, + libc::LOCK_EX => fl.l_type |= libc::F_WRLCK, + libc::LOCK_UN => fl.l_type |= libc::F_UNLCK, + _ => return Err(Error::from_raw_os_error(libc::EINVAL)), + } + + let ret = unsafe { libc::fcntl(file.as_raw_fd(), cmd, &fl) }; + match ret { + // Translate EACCES to EWOULDBLOCK + -1 => match Error::last_os_error().raw_os_error() { + Some(libc::EACCES) => return Err(lock_error()), + _ => return Err(Error::last_os_error()) + }, + _ => Ok(()) + } +} + +pub fn allocated_size(file: &File) -> Result { + file.metadata().map(|m| m.blocks() as u64 * 512) +} + +#[cfg(any(target_os = "linux", + target_os = "freebsd", + target_os = "android", + target_os = "nacl"))] +pub fn allocate(file: &File, len: u64) -> Result<()> { + let ret = unsafe { libc::posix_fallocate(file.as_raw_fd(), 0, len as libc::off_t) }; + if ret == 0 { Ok(()) } else { Err(Error::last_os_error()) } +} + +#[cfg(any(target_os = "macos", target_os = "ios"))] +pub fn allocate(file: &File, len: u64) -> Result<()> { + let stat = try!(file.metadata()); + + if len > stat.blocks() as u64 * 512 { + let mut fstore = libc::fstore_t { + fst_flags: libc::F_ALLOCATECONTIG, + fst_posmode: libc::F_PEOFPOSMODE, + fst_offset: 0, + fst_length: len as libc::off_t, + fst_bytesalloc: 0, + }; + + let ret = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_PREALLOCATE, &fstore) }; + if ret == -1 { + // Unable to allocate contiguous disk space; attempt to allocate non-contiguously. + fstore.fst_flags = libc::F_ALLOCATEALL; + let ret = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_PREALLOCATE, &fstore) }; + if ret == -1 { + return Err(Error::last_os_error()); + } + } + } + + if len > stat.size() as u64 { + file.set_len(len) + } else { + Ok(()) + } +} + +#[cfg(any(target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly", + target_os = "solaris", + target_os = "haiku"))] +pub fn allocate(file: &File, len: u64) -> Result<()> { + // No file allocation API available, just set the length if necessary. + if len > try!(file.metadata()).len() as u64 { + file.set_len(len) + } else { + Ok(()) + } +} + +pub fn statvfs(path: &Path) -> Result { + let cstr = match CString::new(path.as_os_str().as_bytes()) { + Ok(cstr) => cstr, + Err(..) => return Err(Error::new(ErrorKind::InvalidInput, "path contained a null")), + }; + + unsafe { + let mut stat: libc::statvfs = mem::zeroed(); + // danburkert/fs2-rs#1: cast is necessary for platforms where c_char != u8. + if libc::statvfs(cstr.as_ptr() as *const _, &mut stat) != 0 { + Err(Error::last_os_error()) + } else { + Ok(FsStats { + free_space: stat.f_frsize as u64 * stat.f_bfree as u64, + available_space: stat.f_frsize as u64 * stat.f_bavail as u64, + total_space: stat.f_frsize as u64 * stat.f_blocks as u64, + allocation_granularity: stat.f_frsize as u64, + }) + } + } +} + +#[cfg(test)] +mod test { + extern crate tempdir; + extern crate libc; + + use std::fs::{self, File}; + use std::os::unix::io::AsRawFd; + + use {FileExt, lock_contended_error}; + + /// The duplicate method returns a file with a new file descriptor. + #[test] + fn duplicate_new_fd() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + let file2 = file1.duplicate().unwrap(); + assert!(file1.as_raw_fd() != file2.as_raw_fd()); + } + + /// The duplicate method should preservesthe close on exec flag. + #[test] + fn duplicate_cloexec() { + + fn flags(file: &File) -> libc::c_int { + unsafe { libc::fcntl(file.as_raw_fd(), libc::F_GETFL, 0) } + } + + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + let file2 = file1.duplicate().unwrap(); + + assert_eq!(flags(&file1), flags(&file2)); + } + + /// Tests that locking a file descriptor will replace any existing locks + /// held on the file descriptor. + #[test] + fn lock_replace() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + let file2 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + + // Creating a shared lock will drop an exclusive lock. + file1.lock_exclusive().unwrap(); + file1.lock_shared().unwrap(); + file2.lock_shared().unwrap(); + + // Attempting to replace a shared lock with an exclusive lock will fail + // with multiple lock holders, and remove the original shared lock. + assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + file1.lock_shared().unwrap(); + } + + /// Tests that locks are shared among duplicated file descriptors. + #[test] + fn lock_duplicate() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + let file2 = file1.duplicate().unwrap(); + let file3 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + + // Create a lock through fd1, then replace it through fd2. + file1.lock_shared().unwrap(); + file2.lock_exclusive().unwrap(); + assert_eq!(file3.try_lock_shared().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + + // Either of the file descriptors should be able to unlock. + file1.unlock().unwrap(); + file3.lock_shared().unwrap(); + } +} diff --git a/fs2-0.4.3/src/windows.rs b/fs2-0.4.3/src/windows.rs new file mode 100644 index 000000000..0e37c6657 --- /dev/null +++ b/fs2-0.4.3/src/windows.rs @@ -0,0 +1,279 @@ +use std::fs::File; +use std::io::{Error, Result}; +use std::mem; +use std::os::windows::ffi::OsStrExt; +use std::os::windows::io::{AsRawHandle, FromRawHandle}; +use std::path::Path; +use std::ptr; + +use winapi::shared::minwindef::{BOOL, DWORD}; +use winapi::shared::winerror::ERROR_LOCK_VIOLATION; +use winapi::um::fileapi::{FILE_ALLOCATION_INFO, FILE_STANDARD_INFO, GetDiskFreeSpaceW}; +use winapi::um::fileapi::{GetVolumePathNameW, LockFileEx, UnlockFile, SetFileInformationByHandle}; +use winapi::um::handleapi::DuplicateHandle; +use winapi::um::minwinbase::{FileAllocationInfo, FileStandardInfo}; +use winapi::um::minwinbase::{LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK}; +use winapi::um::processthreadsapi::GetCurrentProcess; +use winapi::um::winbase::GetFileInformationByHandleEx; +use winapi::um::winnt::DUPLICATE_SAME_ACCESS; + +use FsStats; + +pub fn duplicate(file: &File) -> Result { + unsafe { + let mut handle = ptr::null_mut(); + let current_process = GetCurrentProcess(); + let ret = DuplicateHandle(current_process, + file.as_raw_handle(), + current_process, + &mut handle, + 0, + true as BOOL, + DUPLICATE_SAME_ACCESS); + if ret == 0 { + Err(Error::last_os_error()) + } else { + Ok(File::from_raw_handle(handle)) + } + } +} + +pub fn allocated_size(file: &File) -> Result { + unsafe { + let mut info: FILE_STANDARD_INFO = mem::zeroed(); + + let ret = GetFileInformationByHandleEx( + file.as_raw_handle(), + FileStandardInfo, + &mut info as *mut _ as *mut _, + mem::size_of::() as DWORD); + + if ret == 0 { + Err(Error::last_os_error()) + } else { + Ok(*info.AllocationSize.QuadPart() as u64) + } + } +} + +pub fn allocate(file: &File, len: u64) -> Result<()> { + if try!(allocated_size(file)) < len { + unsafe { + let mut info: FILE_ALLOCATION_INFO = mem::zeroed(); + *info.AllocationSize.QuadPart_mut() = len as i64; + let ret = SetFileInformationByHandle( + file.as_raw_handle(), + FileAllocationInfo, + &mut info as *mut _ as *mut _, + mem::size_of::() as DWORD); + if ret == 0 { + return Err(Error::last_os_error()); + } + } + } + if try!(file.metadata()).len() < len { + file.set_len(len) + } else { + Ok(()) + } +} + +pub fn lock_shared(file: &File) -> Result<()> { + lock_file(file, 0) +} + +pub fn lock_exclusive(file: &File) -> Result<()> { + lock_file(file, LOCKFILE_EXCLUSIVE_LOCK) +} + +pub fn try_lock_shared(file: &File) -> Result<()> { + lock_file(file, LOCKFILE_FAIL_IMMEDIATELY) +} + +pub fn try_lock_exclusive(file: &File) -> Result<()> { + lock_file(file, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY) +} + +pub fn unlock(file: &File) -> Result<()> { + unsafe { + let ret = UnlockFile(file.as_raw_handle(), 0, 0, !0, !0); + if ret == 0 { Err(Error::last_os_error()) } else { Ok(()) } + } +} + +pub fn lock_error() -> Error { + Error::from_raw_os_error(ERROR_LOCK_VIOLATION as i32) +} + +fn lock_file(file: &File, flags: DWORD) -> Result<()> { + unsafe { + let mut overlapped = mem::zeroed(); + let ret = LockFileEx(file.as_raw_handle(), flags, 0, !0, !0, &mut overlapped); + if ret == 0 { Err(Error::last_os_error()) } else { Ok(()) } + } +} + +fn volume_path(path: &Path, volume_path: &mut [u16]) -> Result<()> { + let path_utf8: Vec = path.as_os_str().encode_wide().chain(Some(0)).collect(); + unsafe { + let ret = GetVolumePathNameW(path_utf8.as_ptr(), + volume_path.as_mut_ptr(), + volume_path.len() as DWORD); + if ret == 0 { Err(Error::last_os_error()) } else { Ok(()) + } + } +} + +pub fn statvfs(path: &Path) -> Result { + let root_path: &mut [u16] = &mut [0; 261]; + try!(volume_path(path, root_path)); + unsafe { + + let mut sectors_per_cluster = 0; + let mut bytes_per_sector = 0; + let mut number_of_free_clusters = 0; + let mut total_number_of_clusters = 0; + let ret = GetDiskFreeSpaceW(root_path.as_ptr(), + &mut sectors_per_cluster, + &mut bytes_per_sector, + &mut number_of_free_clusters, + &mut total_number_of_clusters); + if ret == 0 { + Err(Error::last_os_error()) + } else { + let bytes_per_cluster = sectors_per_cluster as u64 * bytes_per_sector as u64; + let free_space = bytes_per_cluster * number_of_free_clusters as u64; + let total_space = bytes_per_cluster * total_number_of_clusters as u64; + Ok(FsStats { + free_space: free_space, + available_space: free_space, + total_space: total_space, + allocation_granularity: bytes_per_cluster, + }) + } + } +} + +#[cfg(test)] +mod test { + + extern crate tempdir; + + use std::fs; + use std::os::windows::io::AsRawHandle; + + use {FileExt, lock_contended_error}; + + /// The duplicate method returns a file with a new file handle. + #[test] + fn duplicate_new_handle() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().write(true).create(true).open(&path).unwrap(); + let file2 = file1.duplicate().unwrap(); + assert!(file1.as_raw_handle() != file2.as_raw_handle()); + } + + /// A duplicated file handle does not have access to the original handle's locks. + #[test] + fn lock_duplicate_handle_independence() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file2 = file1.duplicate().unwrap(); + + // Locking the original file handle will block the duplicate file handle from opening a lock. + file1.lock_shared().unwrap(); + assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + + // Once the original file handle is unlocked, the duplicate handle can proceed with a lock. + file1.unlock().unwrap(); + file2.lock_exclusive().unwrap(); + } + + /// A file handle may not be exclusively locked multiple times, or exclusively locked and then + /// shared locked. + #[test] + fn lock_non_reentrant() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + // Multiple exclusive locks fails. + file.lock_exclusive().unwrap(); + assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + file.unlock().unwrap(); + + // Shared then Exclusive locks fails. + file.lock_shared().unwrap(); + assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + } + + /// A file handle can hold an exclusive lock and any number of shared locks, all of which must + /// be unlocked independently. + #[test] + fn lock_layering() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + // Open two shared locks on the file, and then try and fail to open an exclusive lock. + file.lock_exclusive().unwrap(); + file.lock_shared().unwrap(); + file.lock_shared().unwrap(); + assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + + // Pop one of the shared locks and try again. + file.unlock().unwrap(); + assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + + // Pop the second shared lock and try again. + file.unlock().unwrap(); + assert_eq!(file.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + + // Pop the exclusive lock and finally succeed. + file.unlock().unwrap(); + file.lock_exclusive().unwrap(); + } + + /// A file handle with multiple open locks will have all locks closed on drop. + #[test] + fn lock_layering_cleanup() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file2 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + + // Open two shared locks on the file, and then try and fail to open an exclusive lock. + file1.lock_shared().unwrap(); + assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + + drop(file1); + file2.lock_exclusive().unwrap(); + } + + /// A file handle's locks will not be released until the original handle and all of its + /// duplicates have been closed. This on really smells like a bug in Windows. + #[test] + fn lock_duplicate_cleanup() { + let tempdir = tempdir::TempDir::new("fs2").unwrap(); + let path = tempdir.path().join("fs2"); + let file1 = fs::OpenOptions::new().read(true).write(true).create(true).open(&path).unwrap(); + let file2 = file1.duplicate().unwrap(); + + // Open a lock on the original handle, then close it. + file1.lock_shared().unwrap(); + drop(file1); + + // Attempting to create a lock on the file with the duplicate handle will fail. + assert_eq!(file2.try_lock_exclusive().unwrap_err().raw_os_error(), + lock_contended_error().raw_os_error()); + } +} diff --git a/fuchsia-zircon-0.3.3/.cargo-checksum.json b/fuchsia-zircon-0.3.3/.cargo-checksum.json new file mode 100644 index 000000000..fa740b893 --- /dev/null +++ b/fuchsia-zircon-0.3.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{},"package":"2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"} \ No newline at end of file diff --git a/fuchsia-zircon-0.3.3/BUILD.gn b/fuchsia-zircon-0.3.3/BUILD.gn new file mode 100644 index 000000000..1edb419d8 --- /dev/null +++ b/fuchsia-zircon-0.3.3/BUILD.gn @@ -0,0 +1,14 @@ +# Copyright 2017 The Fuchsia Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/rust/rust_library.gni") + +rust_library("fuchsia-zircon") { + deps = [ + "//garnet/public/rust/crates/fuchsia-zircon/fuchsia-zircon-sys", + "//third_party/rust-crates:bitflags-0.7.0", + ] + + with_tests = true +} diff --git a/fuchsia-zircon-0.3.3/Cargo.toml b/fuchsia-zircon-0.3.3/Cargo.toml new file mode 100644 index 000000000..4f8cd92b0 --- /dev/null +++ b/fuchsia-zircon-0.3.3/Cargo.toml @@ -0,0 +1,24 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "fuchsia-zircon" +version = "0.3.3" +authors = ["Raph Levien "] +description = "Rust bindings for the Zircon kernel" +license = "BSD-3-Clause" +repository = "https://fuchsia.googlesource.com/garnet/" +[dependencies.bitflags] +version = "1.0.0" + +[dependencies.fuchsia-zircon-sys] +version = "0.3.3" diff --git a/fuchsia-zircon-0.3.3/LICENSE b/fuchsia-zircon-0.3.3/LICENSE new file mode 100644 index 000000000..ac6402fd9 --- /dev/null +++ b/fuchsia-zircon-0.3.3/LICENSE @@ -0,0 +1,27 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/fuchsia-zircon-0.3.3/README.md b/fuchsia-zircon-0.3.3/README.md new file mode 100644 index 000000000..9a597e097 --- /dev/null +++ b/fuchsia-zircon-0.3.3/README.md @@ -0,0 +1,12 @@ +Rust bindings for Zircon kernel +================================ + +This repository contains Rust language bindings for Zircon kernel syscalls. The +main crate contains type-safe wrappers, while the inner "sys" crate contains the +raw types and FFI declarations. + +There are two ways to build Rust artifacts targeting Fuchsia; using the +[Fargo](https://fuchsia.googlesource.com/fargo/) cross compiling tool or +including your [artifact in the GN +build](https://fuchsia.googlesource.com/docs/+/master/rust.md). Of the two, +Fargo is likely better for exploration and experimentation. diff --git a/fuchsia-zircon-0.3.3/examples/BUILD.gn b/fuchsia-zircon-0.3.3/examples/BUILD.gn new file mode 100644 index 000000000..dee61f582 --- /dev/null +++ b/fuchsia-zircon-0.3.3/examples/BUILD.gn @@ -0,0 +1,17 @@ +# Copyright 2017 The Fuchsia Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/package.gni") + +package("zircon_rust_examples") { + system_image = true + + deps = [ + "zx_toy", + ] + + binaries = [ { + name = "example_zx_toy" + } ] +} diff --git a/fuchsia-zircon-0.3.3/src/channel.rs b/fuchsia-zircon-0.3.3/src/channel.rs new file mode 100644 index 000000000..44ffc6cd9 --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/channel.rs @@ -0,0 +1,418 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for Zircon channel objects. + +use {AsHandleRef, HandleBased, Handle, HandleRef, Peered, Status, Time, usize_into_u32, size_to_u32_sat}; +use {sys, ok}; +use std::mem; + +/// An object representing a Zircon +/// [channel](https://fuchsia.googlesource.com/zircon/+/master/docs/objects/channel.md). +/// +/// As essentially a subtype of `Handle`, it can be freely interconverted. +#[derive(Debug, Eq, PartialEq, Hash)] +pub struct Channel(Handle); +impl_handle_based!(Channel); +impl Peered for Channel {} + +impl Channel { + /// Create a channel, resulting an a pair of `Channel` objects representing both + /// sides of the channel. Messages written into one maybe read from the opposite. + /// + /// Wraps the + /// [zx_channel_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/channel_create.md) + /// syscall. + pub fn create() -> Result<(Channel, Channel), Status> { + unsafe { + let mut handle0 = 0; + let mut handle1 = 0; + let opts = 0; + ok(sys::zx_channel_create(opts, &mut handle0, &mut handle1))?; + Ok(( + Self::from(Handle::from_raw(handle0)), + Self::from(Handle::from_raw(handle1)) + )) + } + } + + /// Read a message from a channel. Wraps the + /// [zx_channel_read](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/channel_read.md) + /// syscall. + /// + /// If the `MessageBuf` lacks the capacity to hold the pending message, + /// returns an `Err` with the number of bytes and number of handles needed. + /// Otherwise returns an `Ok` with the result as usual. + pub fn read_raw(&self, buf: &mut MessageBuf) + -> Result, (usize, usize)> + { + let opts = 0; + unsafe { + buf.clear(); + let raw_handle = self.raw_handle(); + let mut num_bytes: u32 = size_to_u32_sat(buf.bytes.capacity()); + let mut num_handles: u32 = size_to_u32_sat(buf.handles.capacity()); + let status = ok(sys::zx_channel_read(raw_handle, opts, + buf.bytes.as_mut_ptr(), buf.handles.as_mut_ptr() as *mut _, + num_bytes, num_handles, &mut num_bytes, &mut num_handles)); + if status == Err(Status::BUFFER_TOO_SMALL) { + Err((num_bytes as usize, num_handles as usize)) + } else { + Ok(status.map(|()| { + buf.bytes.set_len(num_bytes as usize); + buf.handles.set_len(num_handles as usize); + })) + } + } + } + + /// Read a message from a channel. + /// + /// Note that this method can cause internal reallocations in the `MessageBuf` + /// if it is lacks capacity to hold the full message. If such reallocations + /// are not desirable, use `read_raw` instead. + pub fn read(&self, buf: &mut MessageBuf) -> Result<(), Status> { + loop { + match self.read_raw(buf) { + Ok(result) => return result, + Err((num_bytes, num_handles)) => { + buf.ensure_capacity_bytes(num_bytes); + buf.ensure_capacity_handles(num_handles); + } + } + } + } + + /// Write a message to a channel. Wraps the + /// [zx_channel_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/channel_write.md) + /// syscall. + pub fn write(&self, bytes: &[u8], handles: &mut Vec) + -> Result<(), Status> + { + let opts = 0; + let n_bytes = try!(usize_into_u32(bytes.len()).map_err(|_| Status::OUT_OF_RANGE)); + let n_handles = try!(usize_into_u32(handles.len()).map_err(|_| Status::OUT_OF_RANGE)); + unsafe { + let status = sys::zx_channel_write(self.raw_handle(), opts, bytes.as_ptr(), n_bytes, + handles.as_ptr() as *const sys::zx_handle_t, n_handles); + ok(status)?; + // Handles were successfully transferred, forget them on sender side + handles.set_len(0); + Ok(()) + } + } + + /// Send a message consisting of the given bytes and handles to a channel and await a reply. The + /// bytes should start with a four byte 'txid' which is used to identify the matching reply. + /// + /// Wraps the + /// [zx_channel_call](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/channel_call.md) + /// syscall. + /// + /// Note that unlike [`read`][read], the caller must ensure that the MessageBuf has enough + /// capacity for the bytes and handles which will be received, as replies which are too large + /// are discarded. + /// + /// On failure returns the both the main and read status. + /// + /// [read]: struct.Channel.html#method.read + pub fn call(&self, timeout: Time, bytes: &[u8], handles: &mut Vec, + buf: &mut MessageBuf) -> Result<(), (Status, Status)> + { + let write_num_bytes = try!(usize_into_u32(bytes.len()).map_err( + |_| (Status::OUT_OF_RANGE, Status::OK))); + let write_num_handles = try!(usize_into_u32(handles.len()).map_err( + |_| (Status::OUT_OF_RANGE, Status::OK))); + buf.clear(); + let read_num_bytes: u32 = size_to_u32_sat(buf.bytes.capacity()); + let read_num_handles: u32 = size_to_u32_sat(buf.handles.capacity()); + let args = sys::zx_channel_call_args_t { + wr_bytes: bytes.as_ptr(), + wr_handles: handles.as_ptr() as *const sys::zx_handle_t, + rd_bytes: buf.bytes.as_mut_ptr(), + rd_handles: buf.handles.as_mut_ptr() as *mut _, + wr_num_bytes: write_num_bytes, + wr_num_handles: write_num_handles, + rd_num_bytes: read_num_bytes, + rd_num_handles: read_num_handles, + }; + let mut actual_read_bytes: u32 = 0; + let mut actual_read_handles: u32 = 0; + let mut read_status = Status::OK.into_raw(); + let options = 0; + let status = unsafe { + Status::from_raw( + sys::zx_channel_call( + self.raw_handle(), options, timeout.nanos(), &args, &mut actual_read_bytes, + &mut actual_read_handles, &mut read_status)) + }; + + match status { + Status::OK | + Status::TIMED_OUT | + Status::CALL_FAILED => { + // Handles were successfully transferred, + // even if we didn't get a response, so forget + // them on the sender side. + unsafe { handles.set_len(0); } + } + _ => {} + } + + unsafe { + buf.bytes.set_len(actual_read_bytes as usize); + buf.handles.set_len(actual_read_handles as usize); + } + if Status::OK == status { + Ok(()) + } else { + Err((status, Status::from_raw(read_status))) + } + } +} + +#[test] +pub fn test_handle_repr() { + assert_eq!(::std::mem::size_of::(), 4); + assert_eq!(::std::mem::size_of::(), 4); + assert_eq!(::std::mem::align_of::(), ::std::mem::align_of::()); + + // This test asserts that repr(transparent) still works for Handle -> zx_handle_t + + let n: Vec = vec![0, 100, 2<<32-1]; + let v: Vec = n.iter().map(|h| unsafe { Handle::from_raw(*h) } ).collect(); + + for (handle, raw) in v.iter().zip(n.iter()) { + unsafe { + assert_eq!(*(handle as *const _ as *const [u8; 4]), *(raw as *const _ as *const [u8; 4])); + } + } + + for h in v.into_iter() { + ::std::mem::forget(h); + } +} + +impl AsRef for Channel { + fn as_ref(&self) -> &Self { + &self + } +} + +/// A buffer for _receiving_ messages from a channel. +/// +/// A `MessageBuf` is essentially a byte buffer and a vector of +/// handles, but move semantics for "taking" handles requires special handling. +/// +/// Note that for sending messages to a channel, the caller manages the buffers, +/// using a plain byte slice and `Vec`. +#[derive(Default)] +#[derive(Debug)] +pub struct MessageBuf { + bytes: Vec, + handles: Vec, +} + +impl MessageBuf { + /// Create a new, empty, message buffer. + pub fn new() -> Self { + Default::default() + } + + /// Create a new non-empty message buffer. + pub fn new_with(v: Vec, h: Vec) -> Self { + Self{ + bytes: v, + handles: h, + } + } + + /// Ensure that the buffer has the capacity to hold at least `n_bytes` bytes. + pub fn ensure_capacity_bytes(&mut self, n_bytes: usize) { + ensure_capacity(&mut self.bytes, n_bytes); + } + + /// Ensure that the buffer has the capacity to hold at least `n_handles` handles. + pub fn ensure_capacity_handles(&mut self, n_handles: usize) { + ensure_capacity(&mut self.handles, n_handles); + } + + /// Ensure that at least n_bytes bytes are initialized (0 fill). + pub fn ensure_initialized_bytes(&mut self, n_bytes: usize) { + if n_bytes <= self.bytes.len() { + return; + } + self.bytes.resize(n_bytes, 0); + } + + /// Get a reference to the bytes of the message buffer, as a `&[u8]` slice. + pub fn bytes(&self) -> &[u8] { + self.bytes.as_slice() + } + + /// The number of handles in the message buffer. Note this counts the number + /// available when the message was received; `take_handle` does not affect + /// the count. + pub fn n_handles(&self) -> usize { + self.handles.len() + } + + /// Take the handle at the specified index from the message buffer. If the + /// method is called again with the same index, it will return `None`, as + /// will happen if the index exceeds the number of handles available. + pub fn take_handle(&mut self, index: usize) -> Option { + self.handles.get_mut(index).and_then(|handle| + if handle.is_invalid() { + None + } else { + Some(mem::replace(handle, Handle::invalid())) + } + ) + } + + /// Clear the bytes and handles contained in the buf. This will drop any + /// contained handles, resulting in their resources being freed. + pub fn clear(&mut self) { + self.bytes.clear(); + self.handles.clear(); + } +} + +fn ensure_capacity(vec: &mut Vec, size: usize) { + let len = vec.len(); + if size > len { + vec.reserve(size - len); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use {DurationNum, Rights, Signals, Vmo}; + use std::thread; + + #[test] + fn channel_basic() { + let (p1, p2) = Channel::create().unwrap(); + + let mut empty = vec![]; + assert!(p1.write(b"hello", &mut empty).is_ok()); + + let mut buf = MessageBuf::new(); + assert!(p2.read(&mut buf).is_ok()); + assert_eq!(buf.bytes(), b"hello"); + } + + #[test] + fn channel_read_raw_too_small() { + let (p1, p2) = Channel::create().unwrap(); + + let mut empty = vec![]; + assert!(p1.write(b"hello", &mut empty).is_ok()); + + let mut buf = MessageBuf::new(); + let result = p2.read_raw(&mut buf); + assert_eq!(result, Err((5, 0))); + assert_eq!(buf.bytes(), b""); + } + + #[test] + fn channel_send_handle() { + let hello_length: usize = 5; + + // Create a pair of channels and a virtual memory object. + let (p1, p2) = Channel::create().unwrap(); + let vmo = Vmo::create(hello_length as u64).unwrap(); + + // Duplicate VMO handle and send it down the channel. + let duplicate_vmo_handle = vmo.duplicate_handle(Rights::SAME_RIGHTS).unwrap().into(); + let mut handles_to_send: Vec = vec![duplicate_vmo_handle]; + assert!(p1.write(b"", &mut handles_to_send).is_ok()); + // Handle should be removed from vector. + assert!(handles_to_send.is_empty()); + + // Read the handle from the receiving channel. + let mut buf = MessageBuf::new(); + assert!(p2.read(&mut buf).is_ok()); + assert_eq!(buf.n_handles(), 1); + // Take the handle from the buffer. + let received_handle = buf.take_handle(0).unwrap(); + // Should not affect number of handles. + assert_eq!(buf.n_handles(), 1); + // Trying to take it again should fail. + assert!(buf.take_handle(0).is_none()); + + // Now to test that we got the right handle, try writing something to it... + let received_vmo = Vmo::from(received_handle); + assert_eq!(received_vmo.write(b"hello", 0).unwrap(), hello_length); + + // ... and reading it back from the original VMO. + let mut read_vec = vec![0; hello_length]; + assert_eq!(vmo.read(&mut read_vec, 0).unwrap(), hello_length); + assert_eq!(read_vec, b"hello"); + } + + #[test] + fn channel_call_timeout() { + let ten_ms = 10.millis(); + + // Create a pair of channels and a virtual memory object. + let (p1, p2) = Channel::create().unwrap(); + let vmo = Vmo::create(0 as u64).unwrap(); + + // Duplicate VMO handle and send it along with the call. + let duplicate_vmo_handle = vmo.duplicate_handle(Rights::SAME_RIGHTS).unwrap().into(); + let mut handles_to_send: Vec = vec![duplicate_vmo_handle]; + let mut buf = MessageBuf::new(); + assert_eq!(p1.call(ten_ms.after_now(), b"call", &mut handles_to_send, &mut buf), + Err((Status::TIMED_OUT, Status::OK))); + // Handle should be removed from vector even though we didn't get a response, as it was + // still sent over the channel. + assert!(handles_to_send.is_empty()); + + // Should be able to read call even though it timed out waiting for a response. + let mut buf = MessageBuf::new(); + assert!(p2.read(&mut buf).is_ok()); + assert_eq!(buf.bytes(), b"call"); + assert_eq!(buf.n_handles(), 1); + } + + #[test] + fn channel_call() { + // Create a pair of channels + let (p1, p2) = Channel::create().unwrap(); + + // create an mpsc channel for communicating the call data for later assertion + let (tx, rx) = ::std::sync::mpsc::channel(); + + // Start a new thread to respond to the call. + thread::spawn(move || { + let mut buf = MessageBuf::new(); + // if either the read or the write fail, this thread will panic, + // resulting in tx being dropped, which will be noticed by the rx. + p2.wait_handle(Signals::CHANNEL_READABLE, 1.seconds().after_now()).expect("callee wait error"); + p2.read(&mut buf).expect("callee read error"); + p2.write(b"txidresponse", &mut vec![]).expect("callee write error"); + tx.send(buf).expect("callee mpsc send error"); + }); + + // Make the call. + let mut buf = MessageBuf::new(); + buf.ensure_capacity_bytes(12); + // NOTE(raggi): CQ has been seeing some long stalls from channel call, + // and it's as yet unclear why. The timeout here has been made much + // larger in order to avoid that, as the issues are not issues with this + // crate's concerns. The timeout is here just to prevent the tests from + // stalling forever if a developer makes a mistake locally in this + // crate. Tests of Zircon behavior or virtualization behavior should be + // covered elsewhere. See ZX-1324. + p1.call(30.seconds().after_now(), b"txidcall", &mut vec![], &mut buf).expect("channel call error"); + assert_eq!(buf.bytes(), b"txidresponse"); + assert_eq!(buf.n_handles(), 0); + + let sbuf = rx.recv().expect("mpsc channel recv error"); + assert_eq!(sbuf.bytes(), b"txidcall"); + assert_eq!(sbuf.n_handles(), 0); + } +} diff --git a/fuchsia-zircon-0.3.3/src/cprng.rs b/fuchsia-zircon-0.3.3/src/cprng.rs new file mode 100644 index 000000000..433ed26d9 --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/cprng.rs @@ -0,0 +1,68 @@ +use {Status, ok, sys}; + +/// Draw random bytes from the kernel's CPRNG to fill the given buffer. Returns the actual number of +/// bytes drawn, which may sometimes be less than the size of the buffer provided. +/// +/// The buffer must have length less than `ZX_CPRNG_DRAW_MAX_LEN`. +/// +/// Wraps the +/// [zx_cprng_draw](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/cprng_draw.md) +/// syscall. +pub fn cprng_draw(buffer: &mut [u8]) -> Result { + let mut actual = 0; + let status = unsafe { sys::zx_cprng_draw(buffer.as_mut_ptr(), buffer.len(), &mut actual) }; + ok(status).map(|()| actual) +} + +/// Mix the given entropy into the kernel CPRNG. +/// +/// The buffer must have length less than `ZX_CPRNG_ADD_ENTROPY_MAX_LEN`. +/// +/// Wraps the +/// [zx_cprng_add_entropy](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/cprng_add_entropy.md) +/// syscall. +pub fn cprng_add_entropy(buffer: &[u8]) -> Result<(), Status> { + let status = unsafe { sys::zx_cprng_add_entropy(buffer.as_ptr(), buffer.len()) }; + ok(status) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn cprng() { + let mut buffer = [0; 20]; + assert_eq!(cprng_draw(&mut buffer), Ok(20)); + let mut first_zero = 0; + let mut last_zero = 0; + for _ in 0..30 { + let mut buffer = [0; 20]; + assert_eq!(cprng_draw(&mut buffer), Ok(20)); + if buffer[0] == 0 { + first_zero += 1; + } + if buffer[19] == 0 { + last_zero += 1; + } + } + assert_ne!(first_zero, 30); + assert_ne!(last_zero, 30); + } + + #[test] + fn cprng_too_large() { + let mut buffer = [0; sys::ZX_CPRNG_DRAW_MAX_LEN + 1]; + assert_eq!(cprng_draw(&mut buffer), Err(Status::INVALID_ARGS)); + + for mut s in buffer.chunks_mut(sys::ZX_CPRNG_DRAW_MAX_LEN) { + assert_eq!(cprng_draw(&mut s), Ok(s.len())); + } + } + + #[test] + fn cprng_add() { + let buffer = [0, 1, 2]; + assert_eq!(cprng_add_entropy(&buffer), Ok(())); + } +} \ No newline at end of file diff --git a/fuchsia-zircon-0.3.3/src/event.rs b/fuchsia-zircon-0.3.3/src/event.rs new file mode 100644 index 000000000..533a8aafc --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/event.rs @@ -0,0 +1,32 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for Zircon event objects. + +use {AsHandleRef, Cookied, HandleBased, Handle, HandleRef, Status}; +use {sys, ok}; + +/// An object representing a Zircon +/// [event object](https://fuchsia.googlesource.com/zircon/+/master/docs/objects/event.md). +/// +/// As essentially a subtype of `Handle`, it can be freely interconverted. +#[derive(Debug, Eq, PartialEq)] +pub struct Event(Handle); +impl_handle_based!(Event); +impl Cookied for Event {} + +impl Event { + /// Create an event object, an object which is signalable but nothing else. Wraps the + /// [zx_event_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/event_create.md) + /// syscall. + pub fn create() -> Result { + let mut out = 0; + let opts = 0; + let status = unsafe { sys::zx_event_create(opts, &mut out) }; + ok(status)?; + unsafe { + Ok(Self::from(Handle::from_raw(out))) + } + } +} diff --git a/fuchsia-zircon-0.3.3/src/eventpair.rs b/fuchsia-zircon-0.3.3/src/eventpair.rs new file mode 100644 index 000000000..6f2d29806 --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/eventpair.rs @@ -0,0 +1,65 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for Zircon event pairs. + +use {AsHandleRef, Cookied, HandleBased, Handle, HandleRef, Peered, Status}; +use {sys, ok}; + +/// An object representing a Zircon +/// [event pair](https://fuchsia.googlesource.com/zircon/+/master/docs/concepts.md#Other-IPC_Events_Event-Pairs_and-User-Signals). +/// +/// As essentially a subtype of `Handle`, it can be freely interconverted. +#[derive(Debug, Eq, PartialEq)] +pub struct EventPair(Handle); +impl_handle_based!(EventPair); +impl Peered for EventPair {} +impl Cookied for EventPair {} + +impl EventPair { + /// Create an event pair, a pair of objects which can signal each other. Wraps the + /// [zx_eventpair_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/eventpair_create.md) + /// syscall. + pub fn create() -> Result<(EventPair, EventPair), Status> { + let mut out0 = 0; + let mut out1 = 0; + let options = 0; + let status = unsafe { sys::zx_eventpair_create(options, &mut out0, &mut out1) }; + ok(status)?; + unsafe { + Ok(( + Self::from(Handle::from_raw(out0)), + Self::from(Handle::from_raw(out1)) + )) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use {DurationNum, Signals}; + + #[test] + fn wait_and_signal_peer() { + let (p1, p2) = EventPair::create().unwrap(); + let eighty_ms = 80.millis(); + + // Waiting on one without setting any signal should time out. + assert_eq!(p2.wait_handle(Signals::USER_0, eighty_ms.after_now()), Err(Status::TIMED_OUT)); + + // If we set a signal, we should be able to wait for it. + assert!(p1.signal_peer(Signals::NONE, Signals::USER_0).is_ok()); + assert_eq!(p2.wait_handle(Signals::USER_0, eighty_ms.after_now()).unwrap(), + Signals::USER_0); + + // Should still work, signals aren't automatically cleared. + assert_eq!(p2.wait_handle(Signals::USER_0, eighty_ms.after_now()).unwrap(), + Signals::USER_0); + + // Now clear it, and waiting should time out again. + assert!(p1.signal_peer(Signals::USER_0, Signals::NONE).is_ok()); + assert_eq!(p2.wait_handle(Signals::USER_0, eighty_ms.after_now()), Err(Status::TIMED_OUT)); + } +} diff --git a/fuchsia-zircon-0.3.3/src/fifo.rs b/fuchsia-zircon-0.3.3/src/fifo.rs new file mode 100644 index 000000000..20af6f523 --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/fifo.rs @@ -0,0 +1,98 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for Zircon fifo objects. + +use {AsHandleRef, HandleBased, Handle, HandleRef, Status}; +use {sys, ok}; + +/// An object representing a Zircon fifo. +/// +/// As essentially a subtype of `Handle`, it can be freely interconverted. +#[derive(Debug, Eq, PartialEq)] +pub struct Fifo(Handle); +impl_handle_based!(Fifo); + +impl Fifo { + /// Create a pair of fifos and return their endpoints. Writing to one endpoint enqueues an + /// element into the fifo from which the opposing endpoint reads. Wraps the + /// [zx_fifo_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/fifo_create.md) + /// syscall. + pub fn create(elem_count: u32, elem_size: u32) + -> Result<(Fifo, Fifo), Status> + { + let mut out0 = 0; + let mut out1 = 0; + let options = 0; + let status = unsafe { + sys::zx_fifo_create(elem_count, elem_size, options, &mut out0, &mut out1) + }; + ok(status)?; + unsafe { Ok(( + Self::from(Handle::from_raw(out0)), + Self::from(Handle::from_raw(out1)) + ))} + } + + /// Attempts to write some number of elements into the fifo. The number of bytes written will be + /// rounded down to a multiple of the fifo's element size. + /// Return value (on success) is number of elements actually written. + /// + /// Wraps + /// [zx_fifo_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/fifo_write.md). + pub fn write(&self, bytes: &[u8]) -> Result { + let mut num_entries_written = 0; + let status = unsafe { + sys::zx_fifo_write(self.raw_handle(), bytes.as_ptr(), bytes.len(), + &mut num_entries_written) + }; + ok(status).map(|()| num_entries_written) + } + + /// Attempts to read some number of elements out of the fifo. The number of bytes read will + /// always be a multiple of the fifo's element size. + /// Return value (on success) is number of elements actually read. + /// + /// Wraps + /// [zx_fifo_read](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/fifo_read.md). + pub fn read(&self, bytes: &mut [u8]) -> Result { + let mut num_entries_read = 0; + let status = unsafe { + sys::zx_fifo_read(self.raw_handle(), bytes.as_mut_ptr(), bytes.len(), + &mut num_entries_read) + }; + ok(status).map(|()| num_entries_read) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn fifo_basic() { + let (fifo1, fifo2) = Fifo::create(4, 2).unwrap(); + + // Trying to write less than one element should fail. + assert_eq!(fifo1.write(b""), Err(Status::OUT_OF_RANGE)); + assert_eq!(fifo1.write(b"h"), Err(Status::OUT_OF_RANGE)); + + // Should write one element "he" and ignore the last half-element as it rounds down. + assert_eq!(fifo1.write(b"hex").unwrap(), 1); + + // Should write three elements "ll" "o " "wo" and drop the rest as it is full. + assert_eq!(fifo1.write(b"llo worlds").unwrap(), 3); + + // Now that the fifo is full any further attempts to write should fail. + assert_eq!(fifo1.write(b"blah blah"), Err(Status::SHOULD_WAIT)); + + // Read all 4 entries from the other end. + let mut read_vec = vec![0; 8]; + assert_eq!(fifo2.read(&mut read_vec).unwrap(), 4); + assert_eq!(read_vec, b"hello wo"); + + // Reading again should fail as the fifo is empty. + assert_eq!(fifo2.read(&mut read_vec), Err(Status::SHOULD_WAIT)); + } +} diff --git a/fuchsia-zircon-0.3.3/src/handle.rs b/fuchsia-zircon-0.3.3/src/handle.rs new file mode 100644 index 000000000..5c50f29f0 --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/handle.rs @@ -0,0 +1,243 @@ +use {Port, Rights, Signals, Status, Time, WaitAsyncOpts, ok, sys}; +use std::marker::PhantomData; +use std::mem; + +/// An object representing a Zircon +/// [handle](https://fuchsia.googlesource.com/zircon/+/master/docs/handles.md). +/// +/// Internally, it is represented as a 32-bit integer, but this wrapper enforces +/// strict ownership semantics. The `Drop` implementation closes the handle. +/// +/// This type represents the most general reference to a kernel object, and can +/// be interconverted to and from more specific types. Those conversions are not +/// enforced in the type system; attempting to use them will result in errors +/// returned by the kernel. These conversions don't change the underlying +/// representation, but do change the type and thus what operations are available. +#[derive(Debug, Eq, PartialEq, Hash)] +pub struct Handle(sys::zx_handle_t); + +impl AsHandleRef for Handle { + fn as_handle_ref(&self) -> HandleRef { + HandleRef { handle: self.0, phantom: Default::default() } + } +} + +impl HandleBased for Handle {} + +impl Drop for Handle { + fn drop(&mut self) { + if self.0 != sys::ZX_HANDLE_INVALID { + unsafe { sys::zx_handle_close(self.0) }; + } + } +} + +impl Handle { + /// Initialize a handle backed by ZX_HANDLE_INVALID, the only safe non-handle. + pub fn invalid() -> Handle { + Handle(sys::ZX_HANDLE_INVALID) + } + + /// If a raw handle is obtained from some other source, this method converts + /// it into a type-safe owned handle. + pub unsafe fn from_raw(raw: sys::zx_handle_t) -> Handle { + Handle(raw) + } + + pub fn is_invalid(&self) -> bool { + self.0 == sys::ZX_HANDLE_INVALID + } + + pub fn replace(self, rights: Rights) -> Result { + let handle = self.0; + let mut out = 0; + let status = unsafe { sys::zx_handle_replace(handle, rights.bits(), &mut out) }; + ok(status).map(|()| Handle(out)) + } +} + +/// A borrowed reference to a `Handle`. +/// +/// Mostly useful as part of a `WaitItem`. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct HandleRef<'a> { + handle: sys::zx_handle_t, + phantom: PhantomData<&'a sys::zx_handle_t>, +} + +impl<'a> HandleRef<'a> { + pub fn raw_handle(&self) -> sys::zx_handle_t { + self.handle + } + + pub fn duplicate(&self, rights: Rights) -> Result { + let handle = self.handle; + let mut out = 0; + let status = unsafe { sys::zx_handle_duplicate(handle, rights.bits(), &mut out) }; + ok(status).map(|()| Handle(out)) + } + + pub fn signal(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> { + let handle = self.handle; + let status = unsafe { sys::zx_object_signal(handle, clear_mask.bits(), set_mask.bits()) }; + ok(status) + } + + pub fn wait(&self, signals: Signals, deadline: Time) -> Result { + let handle = self.handle; + let mut pending = Signals::empty().bits(); + let status = unsafe { + sys::zx_object_wait_one(handle, signals.bits(), deadline.nanos(), &mut pending) + }; + ok(status).map(|()| Signals::from_bits_truncate(pending)) + } + + pub fn wait_async(&self, port: &Port, key: u64, signals: Signals, options: WaitAsyncOpts) + -> Result<(), Status> + { + let handle = self.handle; + let status = unsafe { + sys::zx_object_wait_async( + handle, port.raw_handle(), key, signals.bits(), options as u32) + }; + ok(status) + } +} + +/// A trait to get a reference to the underlying handle of an object. +pub trait AsHandleRef { + /// Get a reference to the handle. One important use of such a reference is + /// for `object_wait_many`. + fn as_handle_ref(&self) -> HandleRef; + + /// Interpret the reference as a raw handle (an integer type). Two distinct + /// handles will have different raw values (so it can perhaps be used as a + /// key in a data structure). + fn raw_handle(&self) -> sys::zx_handle_t { + self.as_handle_ref().raw_handle() + } + + /// Set and clear userspace-accessible signal bits on an object. Wraps the + /// [zx_object_signal](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_signal.md) + /// syscall. + fn signal_handle(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> { + self.as_handle_ref().signal(clear_mask, set_mask) + } + + /// Waits on a handle. Wraps the + /// [zx_object_wait_one](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_wait_one.md) + /// syscall. + fn wait_handle(&self, signals: Signals, deadline: Time) -> Result { + self.as_handle_ref().wait(signals, deadline) + } + + /// Causes packet delivery on the given port when the object changes state and matches signals. + /// [zx_object_wait_async](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_wait_async.md) + /// syscall. + fn wait_async_handle(&self, port: &Port, key: u64, signals: Signals, options: WaitAsyncOpts) + -> Result<(), Status> + { + self.as_handle_ref().wait_async(port, key, signals, options) + } +} + +impl<'a> AsHandleRef for HandleRef<'a> { + fn as_handle_ref(&self) -> HandleRef { *self } +} + +/// A trait implemented by all handle-based types. +/// +/// Note: it is reasonable for user-defined objects wrapping a handle to implement +/// this trait. For example, a specific interface in some protocol might be +/// represented as a newtype of `Channel`, and implement the `as_handle_ref` +/// method and the `From` trait to facilitate conversion from and to the +/// interface. +pub trait HandleBased: AsHandleRef + From + Into { + /// Duplicate a handle, possibly reducing the rights available. Wraps the + /// [zx_handle_duplicate](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/handle_duplicate.md) + /// syscall. + fn duplicate_handle(&self, rights: Rights) -> Result { + self.as_handle_ref().duplicate(rights).map(|handle| Self::from(handle)) + } + + /// Create a replacement for a handle, possibly reducing the rights available. This invalidates + /// the original handle. Wraps the + /// [zx_handle_replace](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/handle_replace.md) + /// syscall. + fn replace_handle(self, rights: Rights) -> Result { + >::into(self) + .replace(rights).map(|handle| Self::from(handle)) + } + + /// Converts the value into its inner handle. + /// + /// This is a convenience function which simply forwards to the `Into` trait. + fn into_handle(self) -> Handle { + self.into() + } + + /// Converts the handle into it's raw representation. + /// + /// The caller takes ownership over the raw handle, and must close or transfer it to avoid a handle leak. + fn into_raw(self) -> sys::zx_handle_t { + let h = self.into_handle(); + let r = h.0; + mem::forget(h); + r + } + + /// Creates an instance of this type from a handle. + /// + /// This is a convenience function which simply forwards to the `From` trait. + fn from_handle(handle: Handle) -> Self { + Self::from(handle) + } + + /// Creates an instance of another handle-based type from this value's inner handle. + fn into_handle_based(self) -> H { + H::from_handle(self.into_handle()) + } + + /// Creates an instance of this type from the inner handle of another + /// handle-based type. + fn from_handle_based(h: H) -> Self { + Self::from_handle(h.into_handle()) + } +} + +/// A trait implemented by all handles for objects which have a peer. +pub trait Peered: HandleBased { + /// Set and clear userspace-accessible signal bits on the object's peer. Wraps the + /// [zx_object_signal_peer](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_signal.md) + /// syscall. + fn signal_peer(&self, clear_mask: Signals, set_mask: Signals) -> Result<(), Status> { + let handle = self.as_handle_ref().handle; + let status = unsafe { + sys::zx_object_signal_peer(handle, clear_mask.bits(), set_mask.bits()) + }; + ok(status) + } +} + +/// A trait implemented by all handles for objects which can have a cookie attached. +pub trait Cookied: HandleBased { + /// Get the cookie attached to this object, if any. Wraps the + /// [zx_object_get_cookie](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/object_get_cookie.md) + /// syscall. + fn get_cookie(&self, scope: &HandleRef) -> Result { + let handle = self.as_handle_ref().handle; + let mut cookie = 0; + let status = unsafe { sys::zx_object_get_cookie(handle, scope.handle, &mut cookie) }; + ok(status).map(|()| cookie) + } + + /// Attach an opaque cookie to this object with the given scope. The cookie may be read or + /// changed in future only with the same scope. Wraps the + /// [zx_object_set_cookie](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/object_set_cookie.md) + /// syscall. + fn set_cookie(&self, scope: &HandleRef, cookie: u64) -> Result<(), Status> { + let handle = self.as_handle_ref().handle; + let status = unsafe { sys::zx_object_set_cookie(handle, scope.handle, cookie) }; + ok(status) + } +} diff --git a/fuchsia-zircon-0.3.3/src/job.rs b/fuchsia-zircon-0.3.3/src/job.rs new file mode 100644 index 000000000..1bb1ef274 --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/job.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for Zircon job. + +use {AsHandleRef, HandleBased, Handle, HandleRef}; + +/// An object representing a Zircon job. +/// +/// As essentially a subtype of `Handle`, it can be freely interconverted. +#[derive(Debug, Eq, PartialEq)] +pub struct Job(Handle); +impl_handle_based!(Job); \ No newline at end of file diff --git a/fuchsia-zircon-0.3.3/src/lib.rs b/fuchsia-zircon-0.3.3/src/lib.rs new file mode 100644 index 000000000..26444402c --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/lib.rs @@ -0,0 +1,365 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for Zircon kernel +//! [syscalls](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls.md). + +#![deny(warnings)] + +#[macro_use] +extern crate bitflags; + +pub extern crate fuchsia_zircon_sys as sys; + +#[deprecated(note="use fuchsia_zircon::sys::ZX_CPRNG_DRAW_MAX_LEN instead")] +#[doc(hidden)] +pub use sys::ZX_CPRNG_DRAW_MAX_LEN; + +// Implements the HandleBased traits for a Handle newtype struct +macro_rules! impl_handle_based { + ($type_name:path) => { + impl AsHandleRef for $type_name { + fn as_handle_ref(&self) -> HandleRef { + self.0.as_handle_ref() + } + } + + impl From for $type_name { + fn from(handle: Handle) -> Self { + $type_name(handle) + } + } + + impl From<$type_name> for Handle { + fn from(x: $type_name) -> Handle { + x.0 + } + } + + impl HandleBased for $type_name {} + } +} + +// Creates associated constants of TypeName of the form +// `pub const NAME: TypeName = TypeName(value);` +macro_rules! assoc_consts { + ($typename:ident, [$($name:ident = $num:expr;)*]) => { + #[allow(non_upper_case_globals)] + impl $typename { + $( + pub const $name: $typename = $typename($num); + )* + } + } +} + +mod channel; +mod cprng; +mod event; +mod eventpair; +mod fifo; +mod handle; +mod job; +mod port; +mod process; +mod rights; +mod socket; +mod signals; +mod status; +mod time; +mod thread; +mod vmar; +mod vmo; + +pub use channel::*; +pub use cprng::*; +pub use event::*; +pub use eventpair::*; +pub use fifo::*; +pub use handle::*; +pub use job::*; +pub use port::*; +pub use process::*; +pub use rights::*; +pub use socket::*; +pub use signals::*; +pub use status::*; +pub use thread::*; +pub use time::*; +pub use vmar::*; +pub use vmo::*; + +/// Prelude containing common utility traits. +/// Designed for use like `use fuchsia_zircon::prelude::*;` +pub mod prelude { + pub use { + AsHandleRef, + Cookied, + DurationNum, + HandleBased, + Peered, + }; +} + +/// Convenience re-export of `Status::ok`. +pub fn ok(raw: sys::zx_status_t) -> Result<(), Status> { + Status::ok(raw) +} + +/// A "wait item" containing a handle reference and information about what signals +/// to wait on, and, on return from `object_wait_many`, which are pending. +#[repr(C)] +#[derive(Debug)] +pub struct WaitItem<'a> { + /// The handle to wait on. + pub handle: HandleRef<'a>, + /// A set of signals to wait for. + pub waitfor: Signals, + /// The set of signals pending, on return of `object_wait_many`. + pub pending: Signals, +} + +/// An identifier to select a particular clock. See +/// [zx_time_get](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/time_get.md) +/// for more information about the possible values. +#[repr(u32)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum ClockId { + /// The number of nanoseconds since the system was powered on. Corresponds to + /// `ZX_CLOCK_MONOTONIC`. + Monotonic = 0, + /// The number of wall clock nanoseconds since the Unix epoch (midnight on January 1 1970) in + /// UTC. Corresponds to ZX_CLOCK_UTC. + UTC = 1, + /// The number of nanoseconds the current thread has been running for. Corresponds to + /// ZX_CLOCK_THREAD. + Thread = 2, +} + +/// Wait on multiple handles. +/// The success return value is a bool indicating whether one or more of the +/// provided handle references was closed during the wait. +/// +/// Wraps the +/// [zx_object_wait_many](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/object_wait_many.md) +/// syscall. +pub fn object_wait_many(items: &mut [WaitItem], deadline: Time) -> Result +{ + let len = try!(usize_into_u32(items.len()).map_err(|_| Status::OUT_OF_RANGE)); + let items_ptr = items.as_mut_ptr() as *mut sys::zx_wait_item_t; + let status = unsafe { sys::zx_object_wait_many( items_ptr, len, deadline.nanos()) }; + if status == sys::ZX_ERR_CANCELED { + return Ok(true) + } + ok(status).map(|()| false) +} + +#[cfg(test)] +mod tests { + use super::*; + #[allow(unused_imports)] + use super::prelude::*; + + #[test] + fn monotonic_time_increases() { + let time1 = Time::get(ClockId::Monotonic); + 1_000.nanos().sleep(); + let time2 = Time::get(ClockId::Monotonic); + assert!(time2 > time1); + } + + #[test] + fn utc_time_increases() { + let time1 = Time::get(ClockId::UTC); + 1_000.nanos().sleep(); + let time2 = Time::get(ClockId::UTC); + assert!(time2 > time1); + } + + #[test] + fn thread_time_increases() { + let time1 = Time::get(ClockId::Thread); + 1_000.nanos().sleep(); + let time2 = Time::get(ClockId::Thread); + assert!(time2 > time1); + } + + #[test] + fn ticks_increases() { + let ticks1 = ticks_get(); + 1_000.nanos().sleep(); + let ticks2 = ticks_get(); + assert!(ticks2 > ticks1); + } + + #[test] + fn tick_length() { + let sleep_time = 1.milli(); + let ticks1 = ticks_get(); + sleep_time.sleep(); + let ticks2 = ticks_get(); + + // The number of ticks should have increased by at least 1 ms worth + let sleep_ticks = sleep_time.millis() * ticks_per_second() / 1000; + assert!(ticks2 >= (ticks1 + sleep_ticks)); + } + + #[test] + fn into_raw() { + let vmo = Vmo::create(1).unwrap(); + let h = vmo.into_raw(); + let vmo2 = Vmo::from(unsafe { Handle::from_raw(h) }); + assert!(vmo2.write(b"1", 0).is_ok()); + } + + #[test] + fn sleep() { + let sleep_ns = 1.millis(); + let time1 = Time::get(ClockId::Monotonic); + sleep_ns.sleep(); + let time2 = Time::get(ClockId::Monotonic); + assert!(time2 > time1 + sleep_ns); + } + + /// Test duplication by means of a VMO + #[test] + fn duplicate() { + let hello_length: usize = 5; + + // Create a VMO and write some data to it. + let vmo = Vmo::create(hello_length as u64).unwrap(); + assert!(vmo.write(b"hello", 0).is_ok()); + + // Replace, reducing rights to read. + let readonly_vmo = vmo.duplicate_handle(Rights::READ).unwrap(); + // Make sure we can read but not write. + let mut read_vec = vec![0; hello_length]; + assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length); + assert_eq!(read_vec, b"hello"); + assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED)); + + // Write new data to the original handle, and read it from the new handle + assert!(vmo.write(b"bye", 0).is_ok()); + assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length); + assert_eq!(read_vec, b"byelo"); + } + + // Test replace by means of a VMO + #[test] + fn replace() { + let hello_length: usize = 5; + + // Create a VMO and write some data to it. + let vmo = Vmo::create(hello_length as u64).unwrap(); + assert!(vmo.write(b"hello", 0).is_ok()); + + // Replace, reducing rights to read. + let readonly_vmo = vmo.replace_handle(Rights::READ).unwrap(); + // Make sure we can read but not write. + let mut read_vec = vec![0; hello_length]; + assert_eq!(readonly_vmo.read(&mut read_vec, 0).unwrap(), hello_length); + assert_eq!(read_vec, b"hello"); + assert_eq!(readonly_vmo.write(b"", 0), Err(Status::ACCESS_DENIED)); + } + + #[test] + fn wait_and_signal() { + let event = Event::create().unwrap(); + let ten_ms = 10.millis(); + + // Waiting on it without setting any signal should time out. + assert_eq!(event.wait_handle( + Signals::USER_0, ten_ms.after_now()), Err(Status::TIMED_OUT)); + + // If we set a signal, we should be able to wait for it. + assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); + assert_eq!(event.wait_handle(Signals::USER_0, ten_ms.after_now()).unwrap(), + Signals::USER_0); + + // Should still work, signals aren't automatically cleared. + assert_eq!(event.wait_handle(Signals::USER_0, ten_ms.after_now()).unwrap(), + Signals::USER_0); + + // Now clear it, and waiting should time out again. + assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); + assert_eq!(event.wait_handle( + Signals::USER_0, ten_ms.after_now()), Err(Status::TIMED_OUT)); + } + + #[test] + fn wait_many_and_signal() { + let ten_ms = 10.millis(); + let e1 = Event::create().unwrap(); + let e2 = Event::create().unwrap(); + + // Waiting on them now should time out. + let mut items = vec![ + WaitItem { handle: e1.as_handle_ref(), waitfor: Signals::USER_0, pending: Signals::NONE }, + WaitItem { handle: e2.as_handle_ref(), waitfor: Signals::USER_1, pending: Signals::NONE }, + ]; + assert_eq!(object_wait_many(&mut items, ten_ms.after_now()), Err(Status::TIMED_OUT)); + assert_eq!(items[0].pending, Signals::NONE); + assert_eq!(items[1].pending, Signals::NONE); + + // Signal one object and it should return success. + assert!(e1.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); + assert!(object_wait_many(&mut items, ten_ms.after_now()).is_ok()); + assert_eq!(items[0].pending, Signals::USER_0); + assert_eq!(items[1].pending, Signals::NONE); + + // Signal the other and it should return both. + assert!(e2.signal_handle(Signals::NONE, Signals::USER_1).is_ok()); + assert!(object_wait_many(&mut items, ten_ms.after_now()).is_ok()); + assert_eq!(items[0].pending, Signals::USER_0); + assert_eq!(items[1].pending, Signals::USER_1); + + // Clear signals on both; now it should time out again. + assert!(e1.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); + assert!(e2.signal_handle(Signals::USER_1, Signals::NONE).is_ok()); + assert_eq!(object_wait_many(&mut items, ten_ms.after_now()), Err(Status::TIMED_OUT)); + assert_eq!(items[0].pending, Signals::NONE); + assert_eq!(items[1].pending, Signals::NONE); + } + + #[test] + fn cookies() { + let event = Event::create().unwrap(); + let scope = Event::create().unwrap(); + + // Getting a cookie when none has been set should fail. + assert_eq!(event.get_cookie(&scope.as_handle_ref()), Err(Status::ACCESS_DENIED)); + + // Set a cookie. + assert_eq!(event.set_cookie(&scope.as_handle_ref(), 42), Ok(())); + + // Should get it back.... + assert_eq!(event.get_cookie(&scope.as_handle_ref()), Ok(42)); + + // but not with the wrong scope! + assert_eq!(event.get_cookie(&event.as_handle_ref()), Err(Status::ACCESS_DENIED)); + + // Can change it, with the same scope... + assert_eq!(event.set_cookie(&scope.as_handle_ref(), 123), Ok(())); + + // but not with a different scope. + assert_eq!(event.set_cookie(&event.as_handle_ref(), 123), Err(Status::ACCESS_DENIED)); + } +} + +pub fn usize_into_u32(n: usize) -> Result { + if n > ::std::u32::MAX as usize || n < ::std::u32::MIN as usize { + return Err(()) + } + Ok(n as u32) +} + +pub fn size_to_u32_sat(n: usize) -> u32 { + if n > ::std::u32::MAX as usize { + return ::std::u32::MAX; + } + if n < ::std::u32::MIN as usize { + return ::std::u32::MIN; + } + n as u32 +} diff --git a/fuchsia-zircon-0.3.3/src/port.rs b/fuchsia-zircon-0.3.3/src/port.rs new file mode 100644 index 000000000..6a9e8a8f7 --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/port.rs @@ -0,0 +1,344 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for Zircon port objects. + +use std::mem; + +use {AsHandleRef, HandleBased, Handle, HandleRef, Signals, Status, Time}; +use {sys, ok}; + +/// An object representing a Zircon +/// [port](https://fuchsia.googlesource.com/zircon/+/master/docs/objects/port.md). +/// +/// As essentially a subtype of `Handle`, it can be freely interconverted. +#[derive(Debug, Eq, PartialEq)] +pub struct Port(Handle); +impl_handle_based!(Port); + +/// A packet sent through a port. This is a type-safe wrapper for +/// [zx_port_packet_t](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_wait.md). +#[derive(PartialEq, Eq, Debug)] +pub struct Packet(sys::zx_port_packet_t); + +/// The contents of a `Packet`. +#[derive(Debug, Copy, Clone)] +pub enum PacketContents { + /// A user-generated packet. + User(UserPacket), + /// A one-shot signal packet generated via `object_wait_async`. + SignalOne(SignalPacket), + /// A repeating signal packet generated via `object_wait_async`. + SignalRep(SignalPacket), + + #[doc(hidden)] + __Nonexhaustive +} + +/// Contents of a user packet (one sent by `port_queue`). This is a type-safe wrapper for +/// [zx_packet_user_t](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_wait.md). +#[derive(Debug, Copy, Clone)] +pub struct UserPacket(sys::zx_packet_user_t); + +/// Contents of a signal packet (one generated by the kernel). This is a type-safe wrapper for +/// [zx_packet_signal_t](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_wait.md). +#[derive(Debug, Copy, Clone)] +pub struct SignalPacket(sys::zx_packet_signal_t); + +impl Packet { + /// Creates a new packet with `UserPacket` data. + pub fn from_user_packet(key: u64, status: i32, user: UserPacket) -> Packet { + Packet( + sys::zx_port_packet_t { + key: key, + packet_type: sys::zx_packet_type_t::ZX_PKT_TYPE_USER, + status: status, + union: user.0, + } + ) + } + + /// The packet's key. + pub fn key(&self) -> u64 { + self.0.key + } + + /// The packet's status. + // TODO: should this type be wrapped? + pub fn status(&self) -> i32 { + self.0.status + } + + /// The contents of the packet. + pub fn contents(&self) -> PacketContents { + if self.0.packet_type == sys::zx_packet_type_t::ZX_PKT_TYPE_USER { + PacketContents::User(UserPacket(self.0.union)) + } else if self.0.packet_type == sys::zx_packet_type_t::ZX_PKT_TYPE_SIGNAL_ONE { + PacketContents::SignalOne(SignalPacket(unsafe { mem::transmute_copy(&self.0.union) })) + } else if self.0.packet_type == sys::zx_packet_type_t::ZX_PKT_TYPE_SIGNAL_REP { + PacketContents::SignalRep(SignalPacket(unsafe { mem::transmute_copy(&self.0.union) })) + } else { + panic!("unexpected packet type"); + } + } +} + +impl UserPacket { + pub fn from_u8_array(val: [u8; 32]) -> UserPacket { + UserPacket(val) + } + + pub fn as_u8_array(&self) -> &[u8; 32] { + &self.0 + } + + pub fn as_mut_u8_array(&mut self) -> &mut [u8; 32] { + &mut self.0 + } +} + +impl SignalPacket { + /// The signals used in the call to `object_wait_async`. + pub fn trigger(&self) -> Signals { + Signals::from_bits_truncate(self.0.trigger) + } + + /// The observed signals. + pub fn observed(&self) -> Signals { + Signals::from_bits_truncate(self.0.observed) + } + + /// A per object count of pending operations. + pub fn count(&self) -> u64 { + self.0.count + } +} + +impl Port { + /// Create an IO port, allowing IO packets to be read and enqueued. + /// + /// Wraps the + /// [zx_port_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_create.md) + /// syscall. + pub fn create() -> Result { + unsafe { + let mut handle = 0; + let opts = 0; + let status = sys::zx_port_create(opts, &mut handle); + ok(status)?; + Ok(Handle::from_raw(handle).into()) + } + } + + /// Attempt to queue a user packet to the IO port. + /// + /// Wraps the + /// [zx_port_queue](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_queue.md) + /// syscall. + pub fn queue(&self, packet: &Packet) -> Result<(), Status> { + let status = unsafe { + sys::zx_port_queue(self.raw_handle(), + &packet.0 as *const sys::zx_port_packet_t, 0) + }; + ok(status) + } + + /// Wait for a packet to arrive on a (V2) port. + /// + /// Wraps the + /// [zx_port_wait](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/port_wait.md) + /// syscall. + pub fn wait(&self, deadline: Time) -> Result { + let mut packet = Default::default(); + let status = unsafe { + sys::zx_port_wait(self.raw_handle(), deadline.nanos(), + &mut packet as *mut sys::zx_port_packet_t, 0) + }; + ok(status)?; + Ok(Packet(packet)) + } + + /// Cancel pending wait_async calls for an object with the given key. + /// + /// Wraps the + /// [zx_port_cancel](https://fuchsia.googlesource.com/zircon/+/HEAD/docs/syscalls/port_cancel.md) + /// syscall. + pub fn cancel(&self, source: &H, key: u64) -> Result<(), Status> where H: HandleBased { + let status = unsafe { + sys::zx_port_cancel(self.raw_handle(), source.raw_handle(), key) + }; + ok(status) + } +} + +/// Options for wait_async. +#[repr(u32)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum WaitAsyncOpts { + Once = sys::ZX_WAIT_ASYNC_ONCE, + Repeating = sys::ZX_WAIT_ASYNC_REPEATING, +} + +#[cfg(test)] +mod tests { + use super::*; + use {DurationNum, Event}; + + #[test] + fn port_basic() { + let ten_ms = 10.millis(); + + let port = Port::create().unwrap(); + + // Waiting now should time out. + assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); + + // Send a valid packet. + let packet = Packet::from_user_packet( + 42, + 123, + UserPacket::from_u8_array([13; 32]), + ); + assert!(port.queue(&packet).is_ok()); + + // Waiting should succeed this time. We should get back the packet we sent. + let read_packet = port.wait(ten_ms.after_now()).unwrap(); + assert_eq!(read_packet, packet); + } + + #[test] + fn wait_async_once() { + let ten_ms = 10.millis(); + let key = 42; + + let port = Port::create().unwrap(); + let event = Event::create().unwrap(); + + assert!(event.wait_async_handle(&port, key, Signals::USER_0 | Signals::USER_1, + WaitAsyncOpts::Once).is_ok()); + + // Waiting without setting any signal should time out. + assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); + + // If we set a signal, we should be able to wait for it. + assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); + let read_packet = port.wait(ten_ms.after_now()).unwrap(); + assert_eq!(read_packet.key(), key); + assert_eq!(read_packet.status(), 0); + match read_packet.contents() { + PacketContents::SignalOne(sig) => { + assert_eq!(sig.trigger(), Signals::USER_0 | Signals::USER_1); + assert_eq!(sig.observed(), Signals::USER_0); + assert_eq!(sig.count(), 1); + } + _ => panic!("wrong packet type"), + } + + // Shouldn't get any more packets. + assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); + + // Calling wait_async again should result in another packet. + assert!(event.wait_async_handle(&port, key, Signals::USER_0, WaitAsyncOpts::Once).is_ok()); + let read_packet = port.wait(ten_ms.after_now()).unwrap(); + assert_eq!(read_packet.key(), key); + assert_eq!(read_packet.status(), 0); + match read_packet.contents() { + PacketContents::SignalOne(sig) => { + assert_eq!(sig.trigger(), Signals::USER_0); + assert_eq!(sig.observed(), Signals::USER_0); + assert_eq!(sig.count(), 1); + } + _ => panic!("wrong packet type"), + } + + // Calling wait_async_handle then cancel, we should not get a packet as cancel will + // remove it from the queue. + assert!(event.wait_async_handle(&port, key, Signals::USER_0, WaitAsyncOpts::Once).is_ok()); + assert!(port.cancel(&event, key).is_ok()); + assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); + + // If the event is signalled after the cancel, we also shouldn't get a packet. + assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); // clear signal + assert!(event.wait_async_handle(&port, key, Signals::USER_0, WaitAsyncOpts::Once).is_ok()); + assert!(port.cancel(&event, key).is_ok()); + assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); + assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); + } + + #[test] + fn wait_async_repeating() { + let ten_ms = 10.millis(); + let key = 42; + + let port = Port::create().unwrap(); + let event = Event::create().unwrap(); + + assert!(event.wait_async_handle(&port, key, Signals::USER_0 | Signals::USER_1, + WaitAsyncOpts::Repeating).is_ok()); + + // Waiting without setting any signal should time out. + assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); + + // If we set a signal, we should be able to wait for it. + assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); + let read_packet = port.wait(ten_ms.after_now()).unwrap(); + assert_eq!(read_packet.key(), key); + assert_eq!(read_packet.status(), 0); + match read_packet.contents() { + PacketContents::SignalRep(sig) => { + assert_eq!(sig.trigger(), Signals::USER_0 | Signals::USER_1); + assert_eq!(sig.observed(), Signals::USER_0); + assert_eq!(sig.count(), 1); + } + _ => panic!("wrong packet type"), + } + + // Should not get any more packets, as ZX_WAIT_ASYNC_REPEATING is edge triggered rather than + // level triggered. + assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); + + // If we clear and resignal, we should get the same packet again, + // even though we didn't call event.wait_async again. + assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); // clear signal + assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); + let read_packet = port.wait(ten_ms.after_now()).unwrap(); + assert_eq!(read_packet.key(), key); + assert_eq!(read_packet.status(), 0); + match read_packet.contents() { + PacketContents::SignalRep(sig) => { + assert_eq!(sig.trigger(), Signals::USER_0 | Signals::USER_1); + assert_eq!(sig.observed(), Signals::USER_0); + assert_eq!(sig.count(), 1); + } + _ => panic!("wrong packet type"), + } + + // Cancelling the wait should stop us getting packets... + assert!(port.cancel(&event, key).is_ok()); + assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); + // ... even if we clear and resignal + assert!(event.signal_handle(Signals::USER_0, Signals::NONE).is_ok()); // clear signal + assert!(event.signal_handle(Signals::NONE, Signals::USER_0).is_ok()); + assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); + + // Calling wait_async again should result in another packet. + assert!(event.wait_async_handle( + &port, key, Signals::USER_0, WaitAsyncOpts::Repeating).is_ok()); + let read_packet = port.wait(ten_ms.after_now()).unwrap(); + assert_eq!(read_packet.key(), key); + assert_eq!(read_packet.status(), 0); + match read_packet.contents() { + PacketContents::SignalRep(sig) => { + assert_eq!(sig.trigger(), Signals::USER_0); + assert_eq!(sig.observed(), Signals::USER_0); + assert_eq!(sig.count(), 1); + } + _ => panic!("wrong packet type"), + } + + // Closing the handle should stop us getting packets. + drop(event); + assert_eq!(port.wait(ten_ms.after_now()), Err(Status::TIMED_OUT)); + } +} diff --git a/fuchsia-zircon-0.3.3/src/process.rs b/fuchsia-zircon-0.3.3/src/process.rs new file mode 100644 index 000000000..b46f1bdd2 --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/process.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for Zircon process. + +use {AsHandleRef, HandleBased, Handle, HandleRef}; + +/// An object representing a Zircon process. +/// +/// As essentially a subtype of `Handle`, it can be freely interconverted. +#[derive(Debug, Eq, PartialEq)] +pub struct Process(Handle); +impl_handle_based!(Process); \ No newline at end of file diff --git a/fuchsia-zircon-0.3.3/src/rights.rs b/fuchsia-zircon-0.3.3/src/rights.rs new file mode 100644 index 000000000..a41ad12f5 --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/rights.rs @@ -0,0 +1,28 @@ +use sys; + +bitflags! { + /// Rights associated with a handle. + /// + /// See [rights.md](https://fuchsia.googlesource.com/zircon/+/master/docs/rights.md) + /// for more information. + #[repr(C)] + pub struct Rights: sys::zx_rights_t { + const NONE = sys::ZX_RIGHT_NONE; + const DUPLICATE = sys::ZX_RIGHT_DUPLICATE; + const TRANSFER = sys::ZX_RIGHT_TRANSFER; + const READ = sys::ZX_RIGHT_READ; + const WRITE = sys::ZX_RIGHT_WRITE; + const EXECUTE = sys::ZX_RIGHT_EXECUTE; + const MAP = sys::ZX_RIGHT_MAP; + const GET_PROPERTY = sys::ZX_RIGHT_GET_PROPERTY; + const SET_PROPERTY = sys::ZX_RIGHT_SET_PROPERTY; + const ENUMERATE = sys::ZX_RIGHT_ENUMERATE; + const DESTROY = sys::ZX_RIGHT_DESTROY; + const SET_POLICY = sys::ZX_RIGHT_SET_POLICY; + const GET_POLICY = sys::ZX_RIGHT_GET_POLICY; + const SIGNAL = sys::ZX_RIGHT_SIGNAL; + const SIGNAL_PEER = sys::ZX_RIGHT_SIGNAL_PEER; + const WAIT = sys::ZX_RIGHT_WAIT; + const SAME_RIGHTS = sys::ZX_RIGHT_SAME_RIGHTS; + } +} \ No newline at end of file diff --git a/fuchsia-zircon-0.3.3/src/signals.rs b/fuchsia-zircon-0.3.3/src/signals.rs new file mode 100644 index 000000000..e5189f5eb --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/signals.rs @@ -0,0 +1,105 @@ +use sys::*; + +bitflags! { + /// Signals that can be waited upon. + /// + /// See + /// [Objects and signals](https://fuchsia.googlesource.com/zircon/+/master/docs/concepts.md#Objects-and-Signals) + /// in the Zircon kernel documentation. Note: the names of signals are still in flux. + #[repr(C)] + pub struct Signals: zx_signals_t { + const NONE = ZX_SIGNAL_NONE; + const OBJECT_ALL = ZX_OBJECT_SIGNAL_ALL; + const USER_ALL = ZX_USER_SIGNAL_ALL; + const OBJECT_0 = ZX_OBJECT_SIGNAL_0; + const OBJECT_1 = ZX_OBJECT_SIGNAL_1; + const OBJECT_2 = ZX_OBJECT_SIGNAL_2; + const OBJECT_3 = ZX_OBJECT_SIGNAL_3; + const OBJECT_4 = ZX_OBJECT_SIGNAL_4; + const OBJECT_5 = ZX_OBJECT_SIGNAL_5; + const OBJECT_6 = ZX_OBJECT_SIGNAL_6; + const OBJECT_7 = ZX_OBJECT_SIGNAL_7; + const OBJECT_8 = ZX_OBJECT_SIGNAL_8; + const OBJECT_9 = ZX_OBJECT_SIGNAL_9; + const OBJECT_10 = ZX_OBJECT_SIGNAL_10; + const OBJECT_11 = ZX_OBJECT_SIGNAL_11; + const OBJECT_12 = ZX_OBJECT_SIGNAL_12; + const OBJECT_13 = ZX_OBJECT_SIGNAL_13; + const OBJECT_14 = ZX_OBJECT_SIGNAL_14; + const OBJECT_15 = ZX_OBJECT_SIGNAL_15; + const OBJECT_16 = ZX_OBJECT_SIGNAL_16; + const OBJECT_17 = ZX_OBJECT_SIGNAL_17; + const OBJECT_18 = ZX_OBJECT_SIGNAL_18; + const OBJECT_19 = ZX_OBJECT_SIGNAL_19; + const OBJECT_20 = ZX_OBJECT_SIGNAL_20; + const OBJECT_21 = ZX_OBJECT_SIGNAL_21; + const OBJECT_22 = ZX_OBJECT_SIGNAL_22; + const OBJECT_HANDLE_CLOSED = ZX_OBJECT_HANDLE_CLOSED; + const USER_0 = ZX_USER_SIGNAL_0; + const USER_1 = ZX_USER_SIGNAL_1; + const USER_2 = ZX_USER_SIGNAL_2; + const USER_3 = ZX_USER_SIGNAL_3; + const USER_4 = ZX_USER_SIGNAL_4; + const USER_5 = ZX_USER_SIGNAL_5; + const USER_6 = ZX_USER_SIGNAL_6; + const USER_7 = ZX_USER_SIGNAL_7; + + const OBJECT_READABLE = ZX_OBJECT_READABLE; + const OBJECT_WRITABLE = ZX_OBJECT_WRITABLE; + const OBJECT_PEER_CLOSED = ZX_OBJECT_PEER_CLOSED; + + // Cancelation (handle was closed while waiting with it) + const HANDLE_CLOSED = ZX_SIGNAL_HANDLE_CLOSED; + + // Event + const EVENT_SIGNALED = ZX_EVENT_SIGNALED; + + // EventPair + const EVENT_PAIR_SIGNALED = ZX_EPAIR_SIGNALED; + const EVENT_PAIR_CLOSED = ZX_EPAIR_CLOSED; + + // Task signals (process, thread, job) + const TASK_TERMINATED = ZX_TASK_TERMINATED; + + // Channel + const CHANNEL_READABLE = ZX_CHANNEL_READABLE; + const CHANNEL_WRITABLE = ZX_CHANNEL_WRITABLE; + const CHANNEL_PEER_CLOSED = ZX_CHANNEL_PEER_CLOSED; + + // Socket + const SOCKET_READABLE = ZX_SOCKET_READABLE; + const SOCKET_WRITABLE = ZX_SOCKET_WRITABLE; + const SOCKET_PEER_CLOSED = ZX_SOCKET_PEER_CLOSED; + + // Port + const PORT_READABLE = ZX_PORT_READABLE; + + // Resource + const RESOURCE_DESTROYED = ZX_RESOURCE_DESTROYED; + const RESOURCE_READABLE = ZX_RESOURCE_READABLE; + const RESOURCE_WRITABLE = ZX_RESOURCE_WRITABLE; + const RESOURCE_CHILD_ADDED = ZX_RESOURCE_CHILD_ADDED; + + // Fifo + const FIFO_READABLE = ZX_FIFO_READABLE; + const FIFO_WRITABLE = ZX_FIFO_WRITABLE; + const FIFO_PEER_CLOSED = ZX_FIFO_PEER_CLOSED; + + // Job + const JOB_NO_PROCESSES = ZX_JOB_NO_PROCESSES; + const JOB_NO_JOBS = ZX_JOB_NO_JOBS; + + // Process + const PROCESS_TERMINATED = ZX_PROCESS_TERMINATED; + + // Thread + const THREAD_TERMINATED = ZX_THREAD_TERMINATED; + + // Log + const LOG_READABLE = ZX_LOG_READABLE; + const LOG_WRITABLE = ZX_LOG_WRITABLE; + + // Timer + const TIMER_SIGNALED = ZX_TIMER_SIGNALED; + } +} \ No newline at end of file diff --git a/fuchsia-zircon-0.3.3/src/socket.rs b/fuchsia-zircon-0.3.3/src/socket.rs new file mode 100644 index 000000000..c93e98cb7 --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/socket.rs @@ -0,0 +1,126 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for Zircon sockets. + +use {AsHandleRef, HandleBased, Handle, HandleRef, Peered}; +use {sys, Status, ok}; + +use std::ptr; + +/// An object representing a Zircon +/// [socket](https://fuchsia.googlesource.com/zircon/+/master/docs/concepts.md#Message-Passing_Sockets-and-Channels). +/// +/// As essentially a subtype of `Handle`, it can be freely interconverted. +#[derive(Debug, Eq, PartialEq)] +pub struct Socket(Handle); +impl_handle_based!(Socket); +impl Peered for Socket {} + +impl Socket { + /// Create a socket, accessed through a pair of endpoints. Data written + /// into one may be read from the other. + /// + /// Wraps + /// [zx_socket_create](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_create.md). + pub fn create() -> Result<(Socket, Socket), Status> { + unsafe { + let mut out0 = 0; + let mut out1 = 0; + let opts = 0; + let status = sys::zx_socket_create(opts, &mut out0, &mut out1); + ok(status)?; + Ok(( + Self::from(Handle::from_raw(out0)), + Self::from(Handle::from_raw(out1)) + )) + } + } + + /// Write the given bytes into the socket. + /// Return value (on success) is number of bytes actually written. + /// + /// Wraps + /// [zx_socket_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_write.md). + pub fn write(&self, bytes: &[u8]) -> Result { + let mut actual = 0; + let opts = 0; + let status = unsafe { + sys::zx_socket_write(self.raw_handle(), opts, bytes.as_ptr(), bytes.len(), + &mut actual) + }; + ok(status).map(|()| actual) + } + + /// Read the given bytes from the socket. + /// Return value (on success) is number of bytes actually read. + /// + /// Wraps + /// [zx_socket_read](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_read.md). + pub fn read(&self, bytes: &mut [u8]) -> Result { + let mut actual = 0; + let opts = 0; + let status = unsafe { + sys::zx_socket_read(self.raw_handle(), opts, bytes.as_mut_ptr(), + bytes.len(), &mut actual) + }; + ok(status) + .map(|()| actual) + .map_err(|status| { + // If an error is returned then actual is undefined, so to be safe + // we set it to 0 and ignore any data that is set in bytes. + actual = 0; + status + }) + } + + /// Close half of the socket, so attempts by the other side to write will fail. + /// + /// Implements the `ZX_SOCKET_HALF_CLOSE` option of + /// [zx_socket_write](https://fuchsia.googlesource.com/zircon/+/master/docs/syscalls/socket_write.md). + pub fn half_close(&self) -> Result<(), Status> { + let status = unsafe { sys::zx_socket_write(self.raw_handle(), sys::ZX_SOCKET_HALF_CLOSE, + ptr::null(), 0, ptr::null_mut()) }; + ok(status) + } + + pub fn outstanding_read_bytes(&self) -> Result { + let mut outstanding = 0; + let status = unsafe { + sys::zx_socket_read(self.raw_handle(), 0, ptr::null_mut(), 0, &mut outstanding) + }; + ok(status).map(|()| outstanding) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn socket_basic() { + let (s1, s2) = Socket::create().unwrap(); + + // Write in one end and read it back out the other. + assert_eq!(s1.write(b"hello").unwrap(), 5); + + let mut read_vec = vec![0; 8]; + assert_eq!(s2.read(&mut read_vec).unwrap(), 5); + assert_eq!(&read_vec[0..5], b"hello"); + + // Try reading when there is nothing to read. + assert_eq!(s2.read(&mut read_vec), Err(Status::SHOULD_WAIT)); + + // Close the socket from one end. + assert!(s1.half_close().is_ok()); + assert_eq!(s2.read(&mut read_vec), Err(Status::BAD_STATE)); + assert_eq!(s1.write(b"fail"), Err(Status::BAD_STATE)); + + // Writing in the other direction should still work. + assert_eq!(s1.read(&mut read_vec), Err(Status::SHOULD_WAIT)); + assert_eq!(s2.write(b"back").unwrap(), 4); + assert_eq!(s1.read(&mut read_vec).unwrap(), 4); + assert_eq!(&read_vec[0..4], b"back"); + } +} diff --git a/fuchsia-zircon-0.3.3/src/status.rs b/fuchsia-zircon-0.3.3/src/status.rs new file mode 100644 index 000000000..4f3e38f98 --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/status.rs @@ -0,0 +1,162 @@ +use std::ffi::NulError; +use std::io; +use sys; + +/// Status type indicating the result of a Fuchsia syscall. +/// +/// This type is generally used to indicate the reason for an error. +/// While this type can contain `Status::OK` (`ZX_OK` in C land), elements of this type are +/// generally constructed using the `ok` method, which checks for `ZX_OK` and returns a +/// `Result<(), Status>` appropriately. +#[repr(C)] +#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct Status(sys::zx_status_t); +impl Status { + /// Returns `Ok(())` if the status was `OK`, + /// otherwise returns `Err(status)`. + pub fn ok(raw: sys::zx_status_t) -> Result<(), Status> { + if raw == Status::OK.0 { + Ok(()) + } else { + Err(Status(raw)) + } + } + + pub fn from_raw(raw: sys::zx_status_t) -> Self { + Status(raw) + } + + pub fn into_raw(self) -> sys::zx_status_t { + self.0 + } +} +assoc_consts!(Status, [ + OK = sys::ZX_OK; + INTERNAL = sys::ZX_ERR_INTERNAL; + NOT_SUPPORTED = sys::ZX_ERR_NOT_SUPPORTED; + NO_RESOURCES = sys::ZX_ERR_NO_RESOURCES; + NO_MEMORY = sys::ZX_ERR_NO_MEMORY; + CALL_FAILED = sys::ZX_ERR_CALL_FAILED; + INTERRUPTED_RETRY = sys::ZX_ERR_INTERRUPTED_RETRY; + INVALID_ARGS = sys::ZX_ERR_INVALID_ARGS; + BAD_HANDLE = sys::ZX_ERR_BAD_HANDLE; + WRONG_TYPE = sys::ZX_ERR_WRONG_TYPE; + BAD_SYSCALL = sys::ZX_ERR_BAD_SYSCALL; + OUT_OF_RANGE = sys::ZX_ERR_OUT_OF_RANGE; + BUFFER_TOO_SMALL = sys::ZX_ERR_BUFFER_TOO_SMALL; + BAD_STATE = sys::ZX_ERR_BAD_STATE; + TIMED_OUT = sys::ZX_ERR_TIMED_OUT; + SHOULD_WAIT = sys::ZX_ERR_SHOULD_WAIT; + CANCELED = sys::ZX_ERR_CANCELED; + PEER_CLOSED = sys::ZX_ERR_PEER_CLOSED; + NOT_FOUND = sys::ZX_ERR_NOT_FOUND; + ALREADY_EXISTS = sys::ZX_ERR_ALREADY_EXISTS; + ALREADY_BOUND = sys::ZX_ERR_ALREADY_BOUND; + UNAVAILABLE = sys::ZX_ERR_UNAVAILABLE; + ACCESS_DENIED = sys::ZX_ERR_ACCESS_DENIED; + IO = sys::ZX_ERR_IO; + IO_REFUSED = sys::ZX_ERR_IO_REFUSED; + IO_DATA_INTEGRITY = sys::ZX_ERR_IO_DATA_INTEGRITY; + IO_DATA_LOSS = sys::ZX_ERR_IO_DATA_LOSS; + BAD_PATH = sys::ZX_ERR_BAD_PATH; + NOT_DIR = sys::ZX_ERR_NOT_DIR; + NOT_FILE = sys::ZX_ERR_NOT_FILE; + FILE_BIG = sys::ZX_ERR_FILE_BIG; + NO_SPACE = sys::ZX_ERR_NO_SPACE; + STOP = sys::ZX_ERR_STOP; + NEXT = sys::ZX_ERR_NEXT; +]); + +impl Status { + pub fn into_io_error(self) -> io::Error { + self.into() + } +} + +impl From for Status { + fn from(kind: io::ErrorKind) -> Self { + use std::io::ErrorKind::*; + match kind { + NotFound => Status::NOT_FOUND, + PermissionDenied => Status::ACCESS_DENIED, + ConnectionRefused => Status::IO_REFUSED, + ConnectionAborted => Status::PEER_CLOSED, + AddrInUse => Status::ALREADY_BOUND, + AddrNotAvailable => Status::UNAVAILABLE, + BrokenPipe => Status::PEER_CLOSED, + AlreadyExists => Status::ALREADY_EXISTS, + WouldBlock => Status::SHOULD_WAIT, + InvalidInput => Status::INVALID_ARGS, + TimedOut => Status::TIMED_OUT, + Interrupted => Status::INTERRUPTED_RETRY, + UnexpectedEof | + WriteZero | + ConnectionReset | + NotConnected | + Other | _ => Status::IO, + } + } +} + +impl From for io::ErrorKind { + fn from(status: Status) -> io::ErrorKind { + use std::io::ErrorKind::*; + match status { + Status::INTERRUPTED_RETRY => Interrupted, + Status::BAD_HANDLE => BrokenPipe, + Status::TIMED_OUT => TimedOut, + Status::SHOULD_WAIT => WouldBlock, + Status::PEER_CLOSED => ConnectionAborted, + Status::NOT_FOUND => NotFound, + Status::ALREADY_EXISTS => AlreadyExists, + Status::ALREADY_BOUND => AlreadyExists, + Status::UNAVAILABLE => AddrNotAvailable, + Status::ACCESS_DENIED => PermissionDenied, + Status::IO_REFUSED => ConnectionRefused, + Status::IO_DATA_INTEGRITY => InvalidData, + + Status::BAD_PATH | + Status::INVALID_ARGS | + Status::OUT_OF_RANGE | + Status::WRONG_TYPE => InvalidInput, + + Status::OK | + Status::NEXT | + Status::STOP | + Status::NO_SPACE | + Status::FILE_BIG | + Status::NOT_FILE | + Status::NOT_DIR | + Status::IO_DATA_LOSS | + Status::IO | + Status::CANCELED | + Status::BAD_STATE | + Status::BUFFER_TOO_SMALL | + Status::BAD_SYSCALL | + Status::INTERNAL | + Status::NOT_SUPPORTED | + Status::NO_RESOURCES | + Status::NO_MEMORY | + Status::CALL_FAILED | + _ => Other, + } + } +} + +impl From for Status { + fn from(err: io::Error) -> Status { + err.kind().into() + } +} + +impl From for io::Error { + fn from(status: Status) -> io::Error { + io::Error::from(io::ErrorKind::from(status)) + } +} + +impl From for Status { + fn from(_error: NulError) -> Status { + Status::INVALID_ARGS + } +} diff --git a/fuchsia-zircon-0.3.3/src/thread.rs b/fuchsia-zircon-0.3.3/src/thread.rs new file mode 100644 index 000000000..be482375d --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/thread.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for Zircon thread. + +use {AsHandleRef, HandleBased, Handle, HandleRef}; + +/// An object representing a Zircon thread. +/// +/// As essentially a subtype of `Handle`, it can be freely interconverted. +#[derive(Debug, Eq, PartialEq)] +pub struct Thread(Handle); +impl_handle_based!(Thread); \ No newline at end of file diff --git a/fuchsia-zircon-0.3.3/src/time.rs b/fuchsia-zircon-0.3.3/src/time.rs new file mode 100644 index 000000000..1b1deacee --- /dev/null +++ b/fuchsia-zircon-0.3.3/src/time.rs @@ -0,0 +1,346 @@ +// Copyright 2016 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +//! Type-safe bindings for Zircon timer objects. + +use {AsHandleRef, ClockId, HandleBased, Handle, HandleRef, Status}; +use {sys, ok}; +use std::ops; +use std::time as stdtime; + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Duration(sys::zx_duration_t); + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Time(sys::zx_time_t); + +impl From for Duration { + fn from(dur: stdtime::Duration) -> Self { + Duration::from_seconds(dur.as_secs()) + + Duration::from_nanos(dur.subsec_nanos() as u64) + } +} + +impl From for stdtime::Duration { + fn from(dur: Duration) -> Self { + let secs = dur.seconds(); + let nanos = (dur.nanos() - (secs * 1_000_000_000)) as u32; + stdtime::Duration::new(secs, nanos) + } +} + +impl ops::Add for Time { + type Output = Time; + fn add(self, dur: Duration) -> Time { + Time::from_nanos(dur.nanos() + self.nanos()) + } +} + +impl ops::Add